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;
}