用 std::localtime + std::strftime 是标准、跨平台、线程安全的 time_t 转本地时间字符串方法,需判空、确保缓冲区足够、注意时区与夏令时自动生效,推荐 c++11+ 使用,c++20 前慎用 std::put_time。

time_t 转本地时间字符串,用 std::strftime 最稳妥
直接用 std::localtime + std::strftime 是标准、跨平台、线程安全(C++11 起)的做法。别碰 localtime(C 版本),它返回静态缓冲区指针,多线程下会踩内存。
常见错误是传错参数顺序或忽略 std::tm 必须由 std::localtime 填充——不能自己 new 或 memset 后乱填字段。
-
std::localtime返回的是std::tm*,且可能为nullptr(比如time_t值非法),必须判空 - 目标缓冲区大小要留足空间,比如格式
"%Y-%m-%d %H:%M:%S"至少需要 20 字节,建议用std::array<char></char>避免栈溢出 -
std::strftime返回实际写入字符数(不含结尾\0),返回 0 表示失败(通常是缓冲区太小或格式非法)
格式化时注意夏令时和时区自动生效
std::localtime 会读取系统环境变量(如 TZ)并应用当前时区规则,包括夏令时偏移。不需要手动加减小时数——加了反而错。
典型场景:服务器部署在 UTC 时区但需显示中国用户本地时间,就得提前设好 TZ="Asia/Shanghai"(Linux/macOS)或调用 _putenv("TZ=Asia/Shanghai")(Windows),再调 std::tzset() 生效。
- Windows 下不设
TZ默认用控制面板时区,但子进程可能继承父进程已缓存的时区,std::tzset()必须显式调用 - 格式串里用
%Z可输出时区缩写(如 CST/CDT),但不可靠;%z输出 UTC 偏移(如 +0800),更稳定 - 避免用
%c等 locale 依赖格式,不同系统 locale 设置可能导致输出格式突变
想免缓冲区管理?用 std::put_time(C++20 前需小心)
C++11 引入 std::put_time,配合 std::ostringstream 可避免手动管理 char 缓冲区,但要注意:它底层仍调 std::strftime,且部分老编译器(如 GCC 4.9、MSVC 2015)实现有 bug,%Y 可能输出两位年份。
实操建议:若项目要求 C++11+ 且编译器较新(GCC 5.3+/Clang 3.7+/MSVC 2017+),可放心用;否则回退到 strftime 更稳。
- 写法示例:
oss -
std::put_time不检查std::localtime返回值是否为空,需前置判空 - 它不支持宽字符输出(
std::wostream),需要 wchar_t 字符串得另寻方案
time_t 为负值或极大值时容易崩
time_t 在 32 位系统上通常是 signed 32-bit,范围约 [-2147483648, 2147483647],对应 1901–2038 年。超出则 std::localtime 返回 nullptr,后续调用 strftime 会崩溃。
64 位系统虽扩展了范围,但某些嵌入式 libc 或旧 Android NDK 仍用 32-bit time_t,不能假设安全。
- 务必检查
std::localtime(&t)返回值,不要跳过这步 - 对来自网络或文件的
time_t输入,先做范围校验(例如t >= 0 && t 对应 9999-12-31) - Windows 上
FILETIME转time_t容易溢出,推荐用std::chrono中间转换,而非直转
真正麻烦的不是怎么写,而是忘记检查 std::localtime 返回空指针,以及在不同平台上线程安全和时区行为差异。这两点踩中一个,线上就可能凌晨三点开始吐异常。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











