应使用 std::chrono::system_clock::now() 获取高精度时间点,通过 time_since_epoch() 和 duration_cast<ms>() 转为毫秒数;格式化时需分离秒级(to_time_t + localtime/gmtime)和毫秒余数(%1000),避免直接用 put_time 或手拼字符串。

用 std::chrono 获取当前毫秒时间戳
别碰 time() 或 gettimeofday() ——它们精度不够,跨平台也不稳。C++11 起,std::chrono::system_clock::now() 是唯一靠谱起点。它返回的是一个高精度时间点,但不是整数毫秒,得自己截取。
关键点:不能直接转 long long,必须先用 time_since_epoch() 拿到距纪元的时长,再用 duration_cast<ms>()</ms> 转成毫秒单位:
auto now = std::chrono::system_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch());
long long millis = ms.count(); // 这才是真正的毫秒数(自 1970-01-01)
注意:system_clock 在 Windows 上可能只到 15ms 精度(取决于系统计时器),Linux 通常能到微秒级,但 duration_cast 到毫秒是安全的。
把毫秒时间戳格式化为可读字符串(如 "2024-05-21 14:23:45.123")
标准库不提供直接格式化带毫秒的 system_clock::time_point 的接口,得拆解:先转 time_t 得秒级部分,再单独算毫秒余数。
立即学习“C++免费学习笔记(深入)”;
常见错误是用 std::put_time 直接格式化,但它不支持毫秒占位符(%f 是微秒,且不可移植);也别用 localtime_s/gmtime_r 后手拼字符串——容易时区错乱或线程不安全。
推荐做法:
- 用
std::chrono::system_clock::to_time_t(now)提取秒级时间 - 用
std::gmtime或std::localtime(注意线程安全)转结构体 - 毫秒部分 =
millis % 1000,补零到三位
示例(本地时间):
auto now = std::chrono::system_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()).count();
auto t = std::chrono::system_clock::to_time_t(now);
auto tp = *std::localtime(&t);
std::ostringstream oss;
oss << std::put_time(&tp, "%Y-%m-%d %H:%M:%S");
oss << '.' << std::setfill('0') << std::setw(3) << (ms % 1000);
std::string s = oss.str(); // e.g. "2024-05-21 14:23:45.123"
Windows 下 GetSystemTimeAsFileTime 的坑
有人图快直接调 Win32 API,但 GetSystemTimeAsFileTime 返回的是 FILETIME(100 纳秒单位),不是毫秒。转换时若用 /10000 再 %1000 取毫秒,看似对,实则因整数截断会丢失精度——比如 123456789 纳秒 → 12345 毫秒 + 6789 纳秒,但 123456789 / 10000 == 12345,余数被丢弃了。
更稳妥的做法是先转为 ULARGE_INTEGER,再做模运算:
FILETIME ft; GetSystemTimeAsFileTime(&ft); ULARGE_INTEGER ull; ull.LowPart = ft.dwLowDateTime; ull.HighPart = ft.dwHighDateTime; unsigned long long ms = ull.QuadPart / 10000; // 正确换算 int msec = static_cast<int>(ms % 1000);
但这绕过了 C++ 标准时钟语义,且 Linux 不可用,除非你明确只要 Windows、且追求极致性能。
时区与线程安全的关键细节
std::localtime 不是线程安全的(返回静态缓冲区),多线程下必须用 std::localtime_r(POSIX)或 localtime_s(MSVC)。但 C++ 标准没规定它们的存在,所以跨平台代码里最好封装一层:
比如在 Linux 上用 localtime_r(&t, &tp),Windows 上用 localtime_s(&tp, &t);或者干脆全用 UTC(用 std::gmtime)避免麻烦。
另一个易忽略点:std::chrono::system_clock 表示的是系统实时时钟,它可能被 NTP 调整跳变,不适合测间隔;如果要高精度计时,该用 steady_clock ——但它不能转日期字符串。
毫秒值本身没有时区,但格式化时选 localtime 还是 gmtime,决定了输出是本地时间还是 UTC,这点一旦写死就很难调试。


















