最推荐做法是将std::chrono::system_clock::now()转为std::time_t,再用localtime_r(linux/macos)或localtime_s(windows)解析为struct tm,注意tm_year+1900、tm_mon+1、tm_mday直接使用。

用 std::chrono + std::time_t 获取本地时间的年月日
直接用 std::chrono 本身不提供年月日提取能力,得先转成 std::time_t,再用 localtime 或 localtime_r 解析。这是目前最推荐、跨平台且线程安全(用 localtime_r)的做法。
常见错误是试图只用 system_clock::now() 的 time_point 直接拆解 —— 它只是个纳秒级计数器,没内置日历逻辑。
std::time_t t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());- Linux/macOS 下优先用线程安全的
localtime_r(&t, &tm);Windows 需用localtime_s(&tm, &t) -
tm.tm_year是从 1900 起算的,所以年份要加 1900;tm.tm_mon是 0–11,月份要加 1 - 别忽略
tm.tm_mday是 1–31,不用加减,但容易和tm.tm_day(不存在!)混淆
为什么不用 gettimeofday 或 clock_gettime
这两个是底层时间接口,返回的是自纪元起的秒/纳秒数,和 std::chrono::system_clock::now() 底层本质相同,但缺失时区转换能力。它们不处理夏令时、本地时区偏移,直接转 struct tm 会出错。
比如在 CST(UTC+8)地区调用 clock_gettime(CLOCK_REALTIME, &ts),得到的仍是 UTC 时间戳,localtime 才负责做时区映射。绕过它就等于默认 UTC,结果比本地时间少 8 小时。
-
gettimeofday已被 POSIX 标记为废弃,C++ 中无对应标准封装 -
clock_gettime在 Windows 上不可用,std::chrono已为你屏蔽这些差异 - 硬用它们 + 手动加偏移(如 +28800)极易出错:夏令时切换、不同地区规则不同、闰秒未计入
Windows 下 GetLocalTime 的坑
WinAPI 的 GetLocalTime 看似简单,但它依赖系统当前时区设置,且返回的是 SYSTEMTIME 结构体,字段名和 struct tm 不一致(比如 wYear vs tm_year),混用会导致编译失败或静默错位。
更麻烦的是:它不支持时区切换 —— 如果程序需要支持用户指定时区(如显示东京时间),这条路就走不通。
-
SYSTEMTIME的wMonth是 1–12,不用加 1;但wDayOfWeek是 0=Sunday,和tm.tm_wday一致 - 跨平台项目里混用 WinAPI 会让 Linux 构建直接失败,除非加
#ifdef _WIN32分支,维护成本陡增 - 它不保证线程安全(虽然通常没问题),而
localtime_r/localtime_s明确设计为可重入
示例:安全获取年月日的最小可行代码
#include <chrono>
#include <ctime>
#include <iostream>
int main() {
auto now = std::chrono::system_clock::now();
std::time_t t = std::chrono::system_clock::to_time_t(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;
int day = tm_buf.tm_mday;
std::cout
<p>注意 <code>tm_buf</code> 必须显式初始化(<code>{}</code>),否则 <code>localtime_r</code> 在某些 libc 实现下可能读取未初始化内存;<code>localtime_s</code> 在 Windows 上对未初始化结构体更敏感。</p>
<p>如果只要日期字符串(如 "2024-05-21"),别自己拼接 —— 用 <code>std::put_time</code> 更可靠,它会自动处理补零和 locale 格式,但要注意它依赖 <code>std::locale</code> 设置,某些嵌入式环境可能不支持。</p></iostream></ctime></chrono>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











