推荐用std::chrono::steady_clock::now()配合duration_cast<std::chrono::milliseconds>().count()获取毫秒时间戳,它单调递增、不受系统时间调整影响,适合间隔测量;若需UTC日志时间则用system_clock。

用 std::chrono::steady_clock 获取毫秒时间戳(推荐)
直接用 std::chrono::system_clock 也能拿到时间,但 steady_clock 更适合做间隔测量,不受系统时钟调整影响,且精度足够覆盖毫秒级需求。获取的是从时钟起点开始的毫秒数,转成 long 安全(64 位系统下 long 通常为 64 位,能存约 584 年的毫秒数)。
实操写法:
auto now = std::chrono::steady_clock::now(); long ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
-
time_since_epoch()返回一个duration,不是整数,必须用count()提取数值 - 别漏掉
std::chrono::milliseconds的模板参数,写成milliseconds::rep或直接count()都不行 - 如果目标是 UTC 时间(比如日志打点需对齐系统时间),才换用
system_clock,但要注意它可能因 NTP 调整而跳变
为什么不用 gettimeofday() 或 clock_gettime()
这两个 C 接口确实返回毫秒或纳秒,但跨平台性差:gettimeofday() 在 Windows 上不可用;clock_gettime(CLOCK_MONOTONIC, ...) 在 macOS 上不支持 CLOCK_MONOTONIC,得用 CLOCK_UPTIME_RAW,写法分散、易出错。
更关键的是,它们返回的是结构体(struct timeval 或 struct timespec),手动换算成毫秒容易溢出或截断:
立即学习“C++免费学习笔记(深入)”;
// 错误示范:tv_usec 是微秒,除以 1000 得毫秒,但没考虑进位 long ms = tv.tv_sec * 1000 + tv.tv_usec / 1000; // tv_usec=999999 → 进位丢失
- 用
chrono让编译器帮你处理单位换算和溢出检查 - Windows 下若坚持用 C 接口,
GetSystemTimeAsFileTime()更稳妥,但要转 FILETIME(64 位 100 纳秒单位),再除以 10000 —— 步骤多、易错
long 类型在不同平台的宽度风险
Linux x86_64 和 macOS 下 long 是 64 位,没问题;但 Windows MSVC 下 long 是 32 位(仅约 2147 秒,即 35 分钟),存毫秒会很快溢出。
- 明确需要跨平台时,优先用
int64_t替代long - 如果必须用
long,加编译期断言:static_assert(sizeof(long) >= 8, "long too small for ms timestamp"); - Clang/GCC 可用
__LONG_WIDTH__宏检查,但 MSVC 不支持,所以断言更通用
常见错误:把 time_point 当整数用
有人直接写 long t = std::chrono::steady_clock::now();,编译失败 —— time_point 不可隐式转整数。
- 必须显式通过
time_since_epoch()→duration_cast→count()三步拿到数值 - 漏掉
duration_cast会导致类型不匹配,例如nanoseconds不能直接count()成毫秒值 - 如果只需要相对差值(如耗时统计),两个
time_point相减得到duration,再count()即可,无需转 epoch
毫秒时间戳真正难的不是“怎么拿”,而是“拿完怎么用”——比如存数据库字段类型是否匹配、网络传输时字节序是否一致、日志里要不要补零对齐。这些细节比获取本身更容易埋坑。


















