std::put_time需配合std::localtime使用,因它只接受std::tm*而非time_t;应先调用std::time获取时间戳,再用std::localtime转换为本地时间结构,注意其线程不安全性。

用 std::put_time 配合 std::localtime 最直接
标准库从 C++11 开始提供 std::put_time,它是专为格式化时间设计的流操纵器,比手拼字符串或调用 strftime 更类型安全、更符合 C++ 习惯。
常见错误是直接传 std::time(nullptr) 给 std::put_time —— 它只接受 std::tm*,不是 time_t。必须先转成本地时间结构:
auto now = std::time(nullptr);-
auto tm_ptr = std::localtime(&now);(注意:返回静态缓冲区指针,多线程下不安全) - 再用
std::cout
如果需要线程安全,改用 std::localtime_r(POSIX)或 std::gmtime_s(Windows),但需自己分配 std::tm 对象。
跨平台时避免 std::localtime 的线程安全陷阱
std::localtime 返回指向内部静态缓冲区的指针,多个线程同时调用会互相覆盖。这不是“偶尔出错”,而是必然竞态。
立即学习“C++免费学习笔记(深入)”;
解决方式取决于目标平台:
- Linux/macOS:用
std::localtime_r(&now, &tm_buf),其中tm_buf是你声明的std::tm变量 - Windows:用
std::localtime_s(&tm_buf, &now) - 纯 C++20:可用
std::chrono::zoned_time+std::format(但目前 GCC/Clang 支持有限)
别指望封装一个“通用 wrapper”绕过平台差异 —— 格式化时间本身就是系统级操作,绕不开 tm 结构和本地时区转换。
%Y-%m-%d %H:%M:%S 里每个占位符的实际含义
格式字符串不是魔法,每个符号对应 std::tm 字段的提取逻辑,理解它们能避开低级错误:
-
%Y:4 位年份(如2024),%y是 2 位(24),别混用 -
%m:补零月份数(01–12),%b是英文缩写(Jan) -
%d:补零日期(01–31),%e是空格补位(1),输出不一致 -
%H:24 小时制(00–23),%I是 12 小时制(01–12) -
%M、%S:分钟和秒,都是补零两位数
Windows 下某些旧 CRT 实现对 %e 或 %:z 支持不全,坚持用 %d 和 %H 最稳妥。
性能敏感场景慎用流式输出
std::cout 看似简洁,但每次调用都会触发流缓冲、locale 查表、格式解析 —— 在高频日志中比 <code>strftime 慢 2–3 倍。
如果每秒要格式化上千次时间戳:
- 优先考虑
strftime直接写入固定大小char[20]缓冲区 - 避免动态分配(比如用
std::string接收结果) - 若用
std::format(C++20),确保编译器已启用完整支持(GCC 13+ / Clang 16+),否则回退到strftime
真正卡点的从来不是“怎么写出 YYYY-MM-DD HH:MM:SS”,而是“怎么在 10μs 内稳定写出它”。


















