推荐用 std::chrono::system_clock::now() 获取毫秒级时间戳:auto ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();它跨平台、UTC 无时区陷阱、64 位防溢出,避免 localtime/gmtime/Windows FileTime 等常见错误。

用 std::chrono 获取毫秒级时间戳(推荐)
现代 C++ 最稳妥、跨平台、无时区陷阱的方式是走 std::chrono。它返回的是从系统纪元(通常是 1970-01-01 00:00:00 UTC)开始的纳秒/毫秒计数,不是字符串,也不是 time_t,直接可参与计算。
常见错误现象:用 std::time(nullptr) 再转 std::localtime,结果在夏令时切换日或跨时区机器上偏移 1 小时;或者用 gettimeofday(非标准,Windows 不支持)。
- 获取毫秒时间戳(
long long类型):auto now = std::chrono::system_clock::now(); auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
- 注意
system_clock::now()返回的是 UTC 时间,和本地时区无关,避免了localtime带来的歧义 - 如果只需要秒级精度,用
seconds替换milliseconds,性能略高,但多数日志/埋点场景需要毫秒
为什么不用 time() + gmtime() 手动拼时间戳
有人会把 time_t 转成 tm 结构,再用 mktime 反推——这本质是绕远路,且极易出错。
使用场景:旧项目里看到类似逻辑,或想兼容 C 风格代码;但新代码不建议。
立即学习“C++免费学习笔记(深入)”;
-
mktime默认按本地时区解析tm,哪怕你填的是 UTC 时间,也会被当成本地时间处理,导致结果偏差 8 小时(东八区) -
time_t在某些嵌入式平台是 32 位,2038 年后溢出;std::chrono::system_clock::time_point底层通常用 64 位整数,无此问题 - 多线程下
gmtime返回静态缓冲区指针,不安全;gmtime_r虽然线程安全,但仍是 C 风格,不如chrono直观
Windows 下 GetSystemTimeAsFileTime 的坑
Windows API 提供高精度文件时间,但单位是 100 纳秒,且起点是 1601-01-01(而非 Unix 纪元),直接拿来当时间戳会错得离谱。
错误现象:得到一个超大正整数(如 133554212345678900),误以为是毫秒,结果传给后端被拒绝或解析成公元 4000+ 年。
- 必须减去 Windows 纪元到 Unix 纪元的差值:
116444736000000000(单位:100 纳秒) - 再除以
10000得到毫秒:ULARGE_INTEGER ft; GetSystemTimeAsFileTime(&ft); long long ms = (ft.QuadPart - 116444736000000000LL) / 10000;
- 除非你在写底层驱动或性能敏感模块,否则没必要绕开
std::chrono去调这个 API
时间戳精度与 system_clock 的实际表现
std::chrono::system_clock 理论上支持纳秒,但真实分辨率取决于操作系统和硬件,Windows 通常只有 10–15ms,Linux 一般能到 1ms 左右。
性能影响:频繁调用 system_clock::now() 在某些老版本 libstdc++ 上有轻微开销(内部锁),但 clang libc++ 和较新 GCC 基本无感。
- 别用
std::chrono::high_resolution_clock替代 —— 它不保证是 UTC 时间,有些实现甚至返回的是单调时钟(steady_clock),不能用于生成时间戳 - 如果真需要亚毫秒精度(比如性能 profiling),应明确用
steady_clock测间隔,而不是生成绝对时间戳 - 跨进程/网络传输时间戳时,务必确认双方都用 UTC + 毫秒,避免本地时区悄悄污染
事情说清了就结束。时间戳看着简单,但时区、精度、跨平台三者只要漏掉一个,线上就可能出错——尤其在分布式日志对齐或定时任务触发这类场景里,差一秒都可能连锁反应。











