应先确认毫秒时间戳的时区语义(UTC或本地),再用std::chrono::milliseconds构造time_point,转system_clock::to_time_t后依平台调用localtime_r/gmtime_r或localtime_s/gmtime_s获取tm结构,最后用std::put_time格式化并手动补毫秒。

用 std::chrono 和 std::put_time 转毫秒时间戳为本地时间字符串
毫秒数通常指自 Unix 纪元(1970-01-01 00:00:00 UTC)起经过的毫秒数。C++11 及以后推荐用 std::chrono 处理时间单位,避免手动除法出错或溢出。
关键步骤是:把毫秒数转成 std::chrono::milliseconds → 转成 std::chrono::system_clock::time_point → 转为 std::tm(本地时区)→ 格式化输出。
常见错误是直接用 time_t 强转毫秒值,比如 time_t t = ms / 1000,这会丢掉毫秒精度且忽略时区转换逻辑;更糟的是忽略 std::gmtime 和 std::localtime 的线程不安全问题。
- 务必用
std::chrono::system_clock::from_time_t(std::time_t)的逆向构造方式,而非手算秒数 - 获取本地时间要用
std::localtime_r(Linux/macOS)或localtime_s(Windows),避免std::localtime的静态缓冲区竞争 - 格式化推荐用
std::put_time,比sprintf拼接更安全、可读性更好
auto ms = 1717023456789LL; // 示例毫秒时间戳
auto tp = std::chrono::system_clock::time_point{std::chrono::milliseconds{ms}};
std::time_t t = std::chrono::system_clock::to_time_t(tp);
std::tm tm_buf{};
#ifdef _WIN32
localtime_s(&tm_buf, &t);
#else
localtime_r(&t, &tm_buf);
#endif
std::ostringstream oss;
oss << std::put_time(&tm_buf, "%Y-%m-%d %H:%M:%S");
std::string result = oss.str(); // "2024-05-30 14:57:36"
处理 UTC 时间而非本地时间
如果毫秒时间戳代表 UTC 时间,且你希望输出也是 UTC 格式(比如日志统一用 GMT),就不能调用 localtime_* 系列函数,否则会多加一个时区偏移。
立即学习“C++免费学习笔记(深入)”;
此时应使用 std::gmtime_r(POSIX)或 gmtime_s(Windows),并注意 std::put_time 本身不自动识别时区,它只按传入的 std::tm 结构体字段格式化。
-
std::gmtime_r返回的是 UTC 对应的tm结构,tm.tm_isdst恒为 0 - 若误用
localtime_r处理本应是 UTC 的毫秒值,结果会比真实时间快或慢若干小时 - 没有跨平台的“UTC-safe”标准库函数,必须显式分支处理 Windows/POSIX
毫秒精度要保留?得自己拼接
std::put_time 最细只支持到秒(%S),无法直接输出毫秒。若需形如 "2024-05-30 14:57:36.789",得手动提取毫秒部分。
方法是:用 tp.time_since_epoch().count() % 1000 得到毫秒余数,再格式化为三位数字补零。
- 别用
tp.time_since_epoch().count() / 1000 % 1000—— 这算的是“秒内毫秒”,但容易因整除截断出错 - 正确做法是先转成
std::chrono::milliseconds,再取模:std::chrono::duration_cast<:chrono::milliseconds>(tp.time_since_epoch()).count() % 1000</:chrono::milliseconds> - 补零建议用
std::setfill('0') << std::setw(3),避免字符串拼接出错
Windows 下 localtime_s 编译失败?检查预处理器定义
在 MSVC 中启用 localtime_s 需定义 _CRT_SECURE_NO_WARNINGS 或确保项目设置中启用了安全函数。否则会报错:error C3861: 'localtime_s': identifier not found。
这不是标准 C++ 函数,而是 Microsoft 扩展,且仅在 _SECURE_SCL=1 或特定运行时库下可用。
- 更稳妥的方式是封装一层:检测编译器,Windows 用
localtime_s,其他平台用localtime_r - 别依赖
__STDC_LIB_EXT1__—— C11 的localtime_s在 C++ 标准里未被采纳,多数编译器不支持 - 若用 MinGW 或 Clang on Windows,
localtime_r可能不可用,此时需 fallback 到std::localtime+ 加锁(仅限单线程场景)


















