最推荐用 std::format(C++20):std::string date_str = std::format("{:%Y%m%d}", std::chrono::system_clock::now());它简洁安全、自动处理本地时区、无需手动管理缓冲区且线程安全;若需兼容旧标准,则用 localtime_r + strftime,注意缓冲区≥9字节并检查返回值;避免 std::put_time 因其仍依赖不安全的 localtime 且多一次拷贝;时区需明确区分本地时间与 UTC,跨平台时 gmtime_r 不可用需替换。

用 std::format(C++20)最直接
如果你的编译器支持 C++20 且启用了 std::format(如 GCC 13+、Clang 15+、MSVC 19.30+),这是最简洁安全的方式:
std::string date_str = std::format("{:%Y%m%d}", std::chrono::system_clock::now());它自动处理时区(本地时间需额外转换)、无需手动管理缓冲区,也避免了 strftime 的线程不安全问题。注意:GCC 默认未启用 std::format,需加编译选项 -D_GLIBCXX_USE_CXX11_ABI=1 -std=c++20 并确认标准库版本支持。
用 strftime + localtime_r(C++11 起通用)
兼容性最广,但必须小心线程安全和缓冲区大小:
- 别用
localtime(返回静态指针,多线程下会覆盖) - 用
localtime_r(Linux/glibc)或localtime_s(Windows)替代 - 目标缓冲区至少留 9 字节(
"YYYYMMDD\0") -
strftime返回值为实际写入长度(不含\0),应检查是否为 0(失败)或 ≥8(截断)
char buf[16];<br>std::time_t t = std::time(nullptr);<br>std::tm tm_buf;<br>if (localtime_r(&t, &tm_buf)) {<br> if (strftime(buf, sizeof(buf), "%Y%m%d", &tm_buf) == 8) {<br> std::string date_str = buf;<br> }<br>}
为什么不用 std::put_time 直接转字符串?
std::put_time 本身不生成字符串,它只能输出到流(如 std::ostringstream),间接使用会多一次拷贝,且仍依赖 std::tm 和线程不安全的 std::localtime:
- 若忽略线程安全直接写
std::localtime(&t),在并发场景下可能返回错误日期 -
std::ostringstream构造 +str()调用比strftime多一次内存分配 - 格式字符串写法和
strftime一致,没省事
时区陷阱:system_clock::now() 是 UTC,但 localtime_r 是本地时区
这导致两个路径结果可能不同:
-
std::format默认按本地时区格式化(底层调用localtime类似逻辑) - 如果明确要 UTC 时间(比如日志统一用 GMT),得用
std::gmtime_r+strftime,或 C++20 中用std::chrono::zoned_time配合std::format - 跨平台时,
gmtime_r在 Windows 不可用,得用_gmtime64_s
localtime_r 即可,但得清楚这个隐含假设。立即学习“C++免费学习笔记(深入)”;
真正容易被忽略的是缓冲区大小和线程安全的组合问题——写小了会截断,用错函数会在高并发下偶然出错,而这种 bug 往往压测才暴露。


















