c++oding="utf-8" ?>
c++20前用std::chrono::system_clock::to_time_t转time_t,再调用localtime_r(linux/macos)或localtime_s(windows)获取tm结构体,手动修正tm_year+1900、tm_mon+1;c++20起推荐用zoned_time+year_month_day,自动处理本地日历。

用 std::chrono + std::time_t 获取年月日(C++20 前主流做法)
标准库不提供直接拆解日期的函数,得先转成 std::time_t,再用 localtime_r(Linux/macOS)或 localtime_s(Windows)转为 tm 结构体。注意:localtime 是线程不安全的,别直接用。
实操建议:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
std::chrono::system_clock::now()获取当前时间点,调用.time_since_epoch()再转time_t不必要——直接用std::chrono::system_clock::to_time_t -
tm中的tm_year是从 1900 起算,tm_mon是 0–11(不是 1–12),必须手动修正 - Windows 下必须用
localtime_s(&tm_buf, &t),传入缓冲区地址;Linux/macOS 用localtime_r(&t, &tm_buf)
std::time_t t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::tm tm_buf{};
#if defined(_WIN32)
localtime_s(&tm_buf, &t);
#else
localtime_r(&t, &tm_buf);
#endif
int year = tm_buf.tm_year + 1900;
int month = tm_buf.tm_mon + 1; // 注意加 1
int day = tm_buf.tm_mday;
用 std::format 和 std::chrono::year_month_day(C++20 起推荐)
C++20 引入了真正语义清晰的日期类型,year_month_day 支持直接拆解,且自动处理时区(基于本地日历)。但要注意:它默认按本地日历解释时间点,不是 UTC。
实操建议:
- 必须用
std::chrono::current_zone()->to_local(...)或std::chrono::zoned_time才能确保是本地日期;否则floor<days>(system_clock::now())</days>得到的是 UTC 日历日 -
year_month_day的year()、month()、day()成员函数返回的是封装类型(如std::chrono::year),需调用.value()取整数 - 编译需开启 C++20(
-std=c++20),且 libstdc++/libc++ 版本要新(GCC 12+、Clang 14+)
auto now = std::chrono::system_clock::now();
auto zt = std::chrono::zoned_time{std::chrono::current_zone(), now};
auto ymd = std::chrono::year_month_day{zt.get_local_time()};
int year = int(ymd.year());
int month = unsigned(ymd.month());
int day = unsigned(ymd.day());
跨平台封装一个安全的 get_local_ymd() 函数
实际项目里不会每次都写判断宏和两套逻辑。建议封装成函数,隐藏平台差异和 C++ 标准版本差异。
关键点:
- 不要依赖
__cplusplus宏判断 C++20——某些旧编译器可能误报;改用__cpp_lib_chrono等特性宏更可靠 - 若 C++20 不可用,回退到
time_t+localtime方案时,务必检查localtime_*返回值是否为nullptr(例如系统时区配置异常时) - 返回结构体比传引用参数更清晰,避免意外修改调用方变量
struct YMD { int year, month, day; };
YMD get_local_ymd() {
#if __cpp_lib_chrono >= 201907L
auto zt = std::chrono::zoned_time{std::chrono::current_zone(),
std::chrono::system_clock::now()};
auto ymd = std::chrono::year_month_day{zt.get_local_time()};
return {int(ymd.year()), unsigned(ymd.month()), unsigned(ymd.day())};
#else
std::time_t t = std::chrono::system_clock::to_time_t(
std::chrono::system_clock::now());
std::tm tm_buf{};
if (!localtime_r(&t, &tm_buf)) // Windows 需换为 localtime_s 并检查返回值
return {1970, 1, 1};
return {tm_buf.tm_year + 1900, tm_buf.tm_mon + 1, tm_buf.tm_mday};
#endif
}
容易被忽略的时区与夏令时陷阱
看似只是“取今天日期”,但背后藏着时区转换和夏令时跳变问题。比如在 DST 开始日(如 3 月第二个周日凌晨 2:00 直接跳到 3:00),同一秒对应两个本地时间;而 zoned_time 构造时若传入模糊时间点,行为由实现定义。
所以:
- 永远不要对
system_clock::now()做“减去 8 小时”这种硬编码偏移来模拟本地时间——时区规则会变,城市也可能跨时区调整 - 如果业务要求严格按 UTC 日历(如日志归档、金融结算),就别用
current_zone(),改用sys_days{floor<days>(now)}</days>拆解 - 测试时别只在校验“今天是不是 2024-06-15”,要覆盖夏令时切换前后几分钟、跨年边界、闰秒发生日(虽罕见)等场景
最稳妥的做法是:明确需求到底要“用户所在时区的今日”,还是“服务器所在时区的今日”,还是“UTC 今日”——选错源头,后面所有拆解都可能偏差一天。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










