C++日期&时间知识点汇总
编程小白也能理解的详细指南 | 包含C++11/17/20新特性
📅 日期和时间处理是编程中的重要部分,C++提供了多种处理日期和时间的方式,从传统的C风格方法到现代的C++11/17/20特性。本文将用通俗易懂的方式介绍这些知识点。
📅 为什么需要日期时间处理?
在日常编程中,我们经常需要处理与时间相关的任务:
- 记录事件发生的时间(如日志记录)
- 测量代码执行时间(性能分析)
- 定时任务和调度
- 处理用户输入的日期(如生日)
- 计算时间间隔(如倒计时)
- 生成时间戳
💡 C++提供了多种处理日期和时间的方法,从传统的C风格方法到现代的C++11/17/20特性。
🕰️ C风格日期时间处理
C++继承了C语言的日期时间处理函数,需要包含头文件 <ctime>
1. time_t 和 time() 函数
time_t
是表示时间的基本数据类型,通常是一个整数(从1970年1月1日UTC时间起经过的秒数)。
time()
函数获取当前时间:
#include <ctime> #include <iostream> int main() { time_t now = time(0); // 获取当前时间 std::cout << "当前时间戳: " << now << "秒" << std::endl; return 0; }
2. tm 结构体
tm
是一个结构体,包含日期和时间的各个组成部分:
struct tm { int tm_sec; // 秒 [0-60] int tm_min; // 分 [0-59] int tm_hour; // 时 [0-23] int tm_mday; // 月中的天数 [1-31] int tm_mon; // 月份 [0-11] (0=一月) int tm_year; // 年份(从1900开始) int tm_wday; // 周中的天数 [0-6] (0=周日) int tm_yday; // 年中的天数 [0-365] int tm_isdst; // 夏令时标志 };
3. 时间转换函数
localtime()
- 将time_t转换为本地时间的tm结构gmtime()
- 将time_t转换为UTC时间的tm结构mktime()
- 将tm结构转换为time_t
示例:获取当前日期和时间
#include <ctime> #include <iostream> int main() { time_t now = time(0); tm *ltm = localtime(&now); std::cout << "年: " << 1900 + ltm->tm_year << std::endl; std::cout << "月: " << 1 + ltm->tm_mon << std::endl; std::cout << "日: " << ltm->tm_mday << std::endl; std::cout << "时间: " << ltm->tm_hour << ":"; std::cout << ltm->tm_min << ":" << ltm->tm_sec << std::endl; return 0; }
⏱️ C++11 chrono库
C++11引入了<chrono>
库,提供了更现代、类型安全的时间处理方式。
1. 时间段 (duration)
表示一段时间长度,如秒、毫秒、微秒等。
#include <chrono> #include <iostream> using namespace std::chrono; int main() { // 定义时间段 milliseconds ms(1000); // 1000毫秒 seconds sec = duration_cast<seconds>(ms); // 转换为秒 std::cout << ms.count() << " 毫秒 = "; std::cout << sec.count() << " 秒" << std::endl; return 0; }
2. 时间点 (time_point)
表示一个特定的时间点,通常相对于某个纪元(如1970年1月1日)。
// 获取当前时间点 auto now = system_clock::now(); // 转换为time_t(C风格时间) time_t now_c = system_clock::to_time_t(now);
3. 时钟 (clock)
chrono库提供了几种时钟:
system_clock
- 系统范围的实时时钟(可调整)steady_clock
- 稳定的时钟(不可调整),适用于测量时间间隔high_resolution_clock
- 最高精度的时钟
示例:测量代码执行时间
#include <chrono> #include <iostream> #include <thread> // 用于sleep int main() { auto start = std::chrono::high_resolution_clock::now(); // 模拟耗时操作 std::this_thread::sleep_for(std::chrono::milliseconds(500)); auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); std::cout << "耗时: " << duration.count() << " 毫秒" << std::endl; return 0; }
📆 C++20 日期库
C++20扩展了chrono库,添加了强大的日历和时区支持。
1. 日历类型
year
- 表示年份month
- 表示月份(1-12)day
- 表示一个月中的某天(1-31)year_month_day
- 完整的日期类型
2. 创建日期
#include <chrono> #include <iostream> int main() { using namespace std::chrono; // 创建日期:2023年8月15日 year_month_day date{2023y, August, 15d}; // 检查日期是否有效 if (date.ok()) { std::cout << "日期有效: "; std::cout << static_cast<int>(date.year()) << "-"; std::cout << static_cast<unsigned>(date.month()) << "-"; std::cout << static_cast<unsigned>(date.day()) << std::endl; } return 0; }
3. 日期运算
auto tomorrow = sys_days{2023y/8/15} + days{1}; std::cout << "明天是: " << tomorrow << std::endl; // 计算两个日期之间的天数 auto date1 = 2023y/8/15; auto date2 = 2023y/9/1; auto diff = sys_days{date2} - sys_days{date1}; std::cout << "相差天数: " << diff.count() << std::endl;
💡 C++20日期库提供了更直观、更安全的日期处理方式,避免了C风格函数中的很多陷阱。
🔄 时间类型转换
在实际编程中,经常需要在不同时间表示之间转换:
1. time_t 和 system_clock::time_point 互转
// time_point 转 time_t auto now_tp = system_clock::now(); time_t now_tt = system_clock::to_time_t(now_tp); // time_t 转 time_point time_t tt = time(0); system_clock::time_point tp = system_clock::from_time_t(tt);
2. tm 和 system_clock::time_point 互转
// time_point 转 tm time_t tt = system_clock::to_time_t(tp); tm* timeinfo = localtime(&tt); // tm 转 time_point tm timeinfo = {}; // 初始化为0 timeinfo.tm_year = 123; // 2023年(2023-1900) timeinfo.tm_mon = 7; // 8月(0-based) timeinfo.tm_mday = 15; // 15日 time_t tt = mktime(&timeinfo); auto tp = system_clock::from_time_t(tt);
🖨️ 格式化输出
C++提供了多种方式格式化日期时间输出。
1. C风格格式化 (strftime)
char buffer[80]; time_t now = time(0); tm *ltm = localtime(&now); strftime(buffer, 80, "%Y-%m-%d %H:%M:%S", ltm); std::cout << "格式化时间: " << buffer << std::endl;
2. C++20格式化
#include <chrono> #include <format> // C++20 #include <iostream> int main() { auto now = std::chrono::system_clock::now(); std::cout << std::format("当前时间: {:%Y-%m-%d %H:%M:%S}", now) << std::endl; return 0; }
常用格式化符号:
%Y
- 四位年份(如2023)%m
- 两位月份(01-12)%d
- 两位日期(01-31)%H
- 24小时制小时(00-23)%M
- 分钟(00-59)%S
- 秒(00-60)%F
- 等价于 %Y-%m-%d%T
- 等价于 %H:%M:%S
⚖️ 新旧方法对比
传统C风格方法
优点:
- 简单,易于理解
- 所有C/C++环境都支持
- 轻量级
缺点:
- 类型不安全
- 容易出错(如月份0-based)
- 功能有限
- 时区处理复杂
C++11/17/20 chrono库
优点:
- 类型安全
- 功能强大
- 支持高精度计时
- 更直观的API
- C++20支持日历和时区
缺点:
- 语法较复杂
- 旧编译器支持有限
- C++20部分功能较新
💡 建议: 新项目尽量使用C++11/17/20的chrono库,旧项目维护或兼容性要求高时使用C风格方法。
🔧 实际应用示例
1. 计算程序执行时间
#include <chrono> #include <iostream> #include <thread> int main() { auto start = std::chrono::steady_clock::now(); // 模拟耗时操作 std::this_thread::sleep_for(std::chrono::seconds(2)); auto end = std::chrono::steady_clock::now(); auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); std::cout << "执行时间: " << elapsed.count() << " 毫秒" << std::endl; return 0; }
2. 生成时间戳字符串
#include <chrono> #include <iostream> #include <ctime> #include <sstream> #include <iomanip> std::string current_time() { auto now = std::chrono::system_clock::now(); auto now_c = std::chrono::system_clock::to_time_t(now); std::tm now_tm = *std::localtime(&now_c); std::ostringstream oss; oss << std::put_time(&now_tm, "%Y%m%d_%H%M%S"); return oss.str(); } int main() { std::cout << "时间戳: " << current_time() << std::endl; return 0; }
3. 计算两个日期之间的天数(C++20)
#include <chrono> #include <iostream> using namespace std::chrono; int main() { auto date1 = 2023y/8/15; // 2023年8月15日 auto date2 = 2023y/9/1; // 2023年9月1日 auto days = sys_days{date2} - sys_days{date1}; std::cout << "天数差: " << days.count() << std::endl; return 0; }