std::put_time 是 c++11 起提供的类型安全时间格式化工具,需配合 std::localtime 或 std::gmtime 将 std::time_t 转为 std::tm* 后使用,输出受流 locale 影响。

用 std::put_time 格式化本地时间最直接
标准库从 C++11 起就提供了 std::put_time,配合 std::localtime 或 std::gmtime 就能完成常见时间格式化。它比手拼字符串安全,也比旧式 strftime 更类型安全。
关键点:必须传入 std::tm*,且不能直接对 std::time_t 调用;输出依赖流的 locale(默认通常没问题)。
常见错误现象:std::put_time(t, "%Y-%m-%d") 编译失败——因为 t 是 std::time_t,不是 std::tm*。
- 先调用
std::time(&t)获取当前时间戳 - 再用
std::localtime(&t)转成std::tm*(注意:返回值是静态缓冲区指针,多线程下需用std::localtime_r或封装) - 用
std::cout
示例:
std::time_t t = std::time(nullptr);
std::tm tm_buf{};
#ifdef _WIN32
localtime_s(&tm_buf, &t);
auto* tm_ptr = &tm_buf;
#else
auto* tm_ptr = std::localtime(&t); // POSIX
#endif
std::cout <h3>跨平台处理 <code>std::localtime</code> 线程安全问题</h3><p><code>std::localtime</code> 返回指向静态内存的指针,在多线程中可能被覆盖。Windows 和 Linux 行为不一致,容易引发偶发性时间错乱。</p><p>使用场景:服务端程序、并发日志、定时器回调中调用时间格式化时必须考虑这点。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
- Linux/macOS 推荐用
std::localtime_r(&t, &tm_buf),把结果写入用户提供的std::tm实例 - Windows 用
localtime_s(&tm_buf, &t)(注意参数顺序相反) - 封装一个 inline 函数统一处理,避免散落条件编译
性能影响几乎为零,但能彻底避开竞态。
自定义格式字符串里这些转义要小心
std::put_time 的格式符和 C 的 strftime 完全一致,但有几个高频踩坑点:
-
%y是两位年份(24),%Y是四位(2024)——日志归档时混用会导致路径错乱 -
%H是 24 小时制,%I是 12 小时制,漏掉%p会丢失 AM/PM -
%z输出时区偏移(如 +0800),但 Windows 默认 locale 下可能为空或报错;需要显式设置std::locale("C")或改用%Z(时区缩写) - 中文 Windows 下若未设置 locale,
%c可能输出乱码,建议固定用 ASCII 格式如"%Y/%m/%d %H:%M"
不需要 <chrono></chrono> 也能做毫秒级时间戳
如果只要“当前时间 + 毫秒”,不必动用 std::chrono 那套复杂时钟转换。用 std::time + std::clock_gettime(Linux/macOS)或 GetSystemTimeAsFileTime(Windows)更轻量。
但注意:std::put_time 不支持毫秒,得手动拼接:
- 先用
std::localtime格式化到秒级 - 再用高精度 API 获取毫秒部分(例如
std::chrono::steady_clock::now().time_since_epoch().count() % 1000) - 最后组合输出:
std::cout
这个组合在日志系统里很常见,但要注意 std::setw 和 std::setfill 是流状态,会影响后续输出,记得重置或限定作用域。
实际用起来最麻烦的往往不是格式本身,而是线程安全那块静态缓冲区,还有 Windows 和 POSIX 对 localtime 变体的参数顺序差异。写一次封装函数,后面就省心了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










