strftime必须先用localtime/gmtime将time_t转为struct tm*,否则崩溃;需检查返回值、注意线程安全、缓冲区大小及跨平台差异。

strftime 格式化时间前必须先调用 localtime 或 gmtime
直接传 time_t 给 strftime 会崩溃或输出乱码,因为 strftime 只接受 struct tm* 类型指针。而 time() 返回的是秒数(time_t),得先转成日历时间结构。
- 本地时间用
localtime(&t),注意它返回静态内存地址,多线程下不安全;线程安全版是localtime_r(&t, &tm)(Linux)或localtime_s(&tm, &t)(Windows) - UTC 时间用
gmtime(&t)或对应安全变体 - 别忘了检查返回值是否为
nullptr——比如传了负的time_t值,在某些平台会导致转换失败
格式字符串里常见转义符和易错点
strftime 的格式控制符看着像 printf,但行为差异大,尤其对宽度、填充、本地化敏感。
-
%Y是 4 位年份,%y是 2 位;误用%y在 2025 年会输出25,埋下 Y2K25 风险 -
%H(24 小时)和%I(12 小时)混用会导致上午/下午逻辑错乱,且%I不自动补零,09:05可能变成9:05 -
%Z输出时区缩写(如 PST),但 Windows 下常返回空字符串;跨平台建议改用%z(+0800 格式)或自己拼接 - 中文环境若未调用
setlocale(LC_TIME, ""),%A/%B仍输出英文,但该函数有全局副作用,多线程中慎用
缓冲区大小不够是 segfault 最常见原因
strftime 不做动态分配,全靠你传入的字符数组长度。溢出不会报错,而是静默截断或踩内存。
- 最短安全长度:至少
64字节。例如"%Y-%m-%d %H:%M:%S"最长 19 字符,但加上时区、毫秒扩展、本地化字符(如“星期三”比“Wednesday”长),留余量很关键 - 别用
sizeof(buf)混淆:如果buf是函数参数(即char* buf),sizeof返回指针大小(通常是 8),不是数组长度 - 推荐写法:
char buf[256]; strftime(buf, sizeof(buf), "%F %T", &tm);,sizeof只在栈上数组定义处才有效
C++20 std::format 更安全但兼容性差
如果你项目允许 C++20,std::format 配合 std::chrono::system_clock::now() 能绕过所有 tm 和缓冲区问题,但目前 MSVC 19.3x、GCC 13、Clang 15 才开始稳定支持。
立即学习“C++免费学习笔记(深入)”;
- 示例:
auto now = std::chrono::system_clock::now(); auto s = std::format("{:%Y-%m-%d %H:%M:%S}", now); - 不依赖 C locale,无缓冲区溢出风险,类型安全
- 但旧系统(如 CentOS 7 默认 GCC 4.8)、嵌入式或 ROS1 环境基本不可用,切勿在需要广泛部署的库中默认启用
事情说清了就结束。真正麻烦的从来不是记不住 %Y 和 %y,而是忘记检查 localtime 返回值,或者在 Windows DLL 里调用了 setlocale 导致宿主程序时区错乱。











