
strftime 格式化时间前必须先用 localtime 或 gmtime 转换
直接对 time_t 值调用 strftime 会崩溃或输出空字符串——因为 strftime 只接受 struct tm*,不接受原始时间戳。你得先用 localtime(本地时区)或 gmtime(UTC)把 time_t 转成 struct tm 对象。
常见错误现象:strftime 返回 0、缓冲区内容不变、程序 segfault(尤其在多线程里没加锁用 localtime)。
-
localtime不是线程安全的;高并发场景优先用localtime_r(Linux/macOS)或localtime_s(Windows) - 如果只需要 UTC 时间,用
gmtime更轻量,也避免时区计算开销 - 注意:
localtime返回的是静态内存地址,多次调用会覆盖前一次结果
格式化字符串里 %Y %y %m %d 容易混淆
年份和月份数字的位数、是否补零、是否带世纪,全靠格式符决定,写错一个符号结果就差十年。
-
%Y是 4 位年份(如2024),%y是 2 位(24),别混用 -
%m是带前导零的月份数字(01–12),%-m(Linux)或%#m(Windows)才去零,但跨平台时慎用 -
%d是带零的日期(05),%e是空格补位(5),部分系统不支持%e - 中文 Windows 下若输出乱码,不是格式符问题,而是终端编码或 locale 没设对
缓冲区大小不足导致 strftime 截断或返回 0
strftime 返回值是实际写入字符数(不含结尾 <p><code>strftime 返回值是实际写入字符数(不含结尾 \0),返回 0 表示失败——最常见原因就是目标缓冲区太小。
立即学习“C++免费学习笔记(深入)”;
- 别硬写
char buf[32]就完事;比如"%Y-%m-%d %H:%M:%S"至少要 20 字节,加上时区、毫秒等可能到 64 字节以上 - 安全做法:用
std::vector<char></char>预分配足够空间,或先用strftime(nullptr, 0, ...)测长度(C++11 起支持) - Windows 下某些 locale 设置会让星期/月份名变长(如德语
"Mittwoch"),缓冲区预留余量更关键
C++20 std::format 和 std::chrono::system_clock 更值得优先考虑
如果你能用 C++20,std::format 配合 std::chrono 是比 strftime 更安全、类型更清晰的选择,不用手动管理 struct tm 和缓冲区。
-
std::format("{:%Y-%m-%d %H:%M:%S}", std::chrono::system_clock::now())一行搞定,无缓冲区风险 - 不依赖 C locale,线程安全,且支持编译期检查格式串
- 但注意:MSVC 2022 17.5+、GCC 13、Clang 15 才完整支持;旧项目仍得靠
strftime - 如果必须兼容 C++11/14,
strftime仍是事实标准,只是得把上面三点都踩一遍坑才能稳
真正麻烦的从来不是记几个 % 符号,而是时区转换时机、线程安全性、缓冲区生命周期这三件事谁先出错——它们不会报错,只会悄悄给你一个看起来“差不多”的错时间。










