std::chrono::system_clock::time_point 不能直接拆解为年月日,必须先用 to_time_t 转为 time_t,再用 localtime/gmtime 解包;c++20 推荐用 year_month_day 配合 floor 获取 utc 日期,注意时区与精度问题。

用 std::chrono::system_clock::to_time_t 转成 C 风格时间再拆解
直接从 std::chrono::system_clock::time_point 拿年月日是不行的——它只存自纪元起的纳秒/微秒数,没有内置日期语义。必须先转成 std::time_t,再用 std::localtime 或 std::gmtime 解包。
注意:std::localtime 返回的是本地时区结果,线程不安全(内部用静态缓冲区);多线程下优先用 std::localtime_r(POSIX)或 std::localtime_s(MSVC)。
-
std::chrono::system_clock::to_time_t是唯一标准、可移植的转换入口,别试图手动除以1000000000算秒数 - 如果只要 UTC 日期,用
std::gmtime;要本地日期,用std::localtime(但记得加锁或用线程安全变体) - Windows 下
std::localtime默认是线程安全的,但 Linux/macOS 不是,跨平台代码务必处理
提取年月日字段时别直接访问 tm_year/tm_mon
std::tm 结构体里的字段全是偏移量:比如 tm_year 是“距 1900 年的年数”,tm_mon 是 0–11 的月编号,tm_mday 才是 1–31 的日。直接打印会出错。
常见错误现象:tm_year 输出 124(其实是 2024 年),tm_mon 输出 5(其实是 6 月)。
- 年份 =
tm.tm_year + 1900 - 月份 =
tm.tm_mon + 1 - 日期 =
tm.tm_mday(无需加减) - 小时/分钟/秒同理:只有
tm_hour、tm_min、tm_sec是直观数值
想避免 C 风格时间?C++20 std::format 和 std::chrono::year_month_day 更干净
C++20 引入了真正的日历类型,不用碰 std::tm。核心路径是:system_clock::time_point → sys_days → year_month_day。
示例:
auto now = std::chrono::system_clock::now();
auto dp = std::chrono::floor<:chrono::days>(now);
std::chrono::year_month_day ymd{dp}; // 自动拆出 year, month, day
std::cout (ymd.year()) (ymd.month()) (ymd.day());</:chrono::days>
-
std::chrono::floor<:chrono::days></:chrono::days>截断到当天零点,这是构造year_month_day的必要步骤 -
ymd.year()返回std::chrono::year类型,需显式转int;month()和day()同理 - 此方式默认是 UTC,如需本地时区,得先用
std::chrono::current_zone()转换(C++20 时区支持较新,部分编译器需开启-std=c++20且确认库支持)
别忽略精度丢失和时区隐含行为
system_clock 在不同平台底层实现不同:Linux 通常基于 clock_gettime(CLOCK_REALTIME),Windows 基于 GetSystemTimeAsFileTime,但 to_time_t 一定截断到秒级——毫秒及以下信息会丢。
更隐蔽的问题是:即使你用 C++20 的 year_month_day,system_clock::now() 本身仍是 UTC 时间点,所有“今天”“本月”的计算都基于 UTC,不是你的本地日历。
- 如果业务逻辑依赖本地日历(比如“用户今天签到”),必须显式转换时区,不能只靠
localtime或current_zone()的默认行为 - 某些嵌入式或旧系统上
system_clock可能不支持纳秒精度,time_since_epoch().count()返回的是微秒甚至毫秒,影响截断逻辑 - 跨天边界操作(比如“昨天凌晨”)建议统一用
sys_days加减days{1},比手动算秒数可靠
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











