




std::put_time 输出空或乱码的根本原因是未显式设置 locale:必须对流调用 .imbue(std::locale("")),仅调用 std::setlocale 无效,且嵌入式环境可能因缺失 locale 而静默失败。
直接用 std::put_time 配合 std::localtime 或 std::gmtime 就能输出格式化时间,但必须注意时区、线程安全和 locale 设置这三个坑。
std::put_time 有时输出空或乱码?根本原因是没正确设置 locale:默认全局 locale 不保证支持 std::put_time 所需的 facet。不显式 imbue,std::ostringstream 或 std::cout 可能直接跳过格式化,返回空字符串。
.imbue(std::locale(""))(空字符串表示系统本地 locale)std::setlocale(LC_ALL, ""),它不影响 C++ iostream 的 facet
std::put_time 会静默失败示例:
std::time_t t = std::time(nullptr);
std::tm* lt = std::localtime(&t);
std::ostringstream oss;
oss.imbue(std::locale("")); // 关键!
oss << std::put_time(lt, "%Y-%m-%d %H:%M:%S");
std::string s = oss.str(); // 正确得到 "2024-06-15 14:23:05"
std::localtime 和 std::gmtime 的线程安全差异std::localtime 和 std::gmtime 返回指向静态缓冲区的指针,在多线程下会互相覆盖 —— 这是 C 标准库遗留问题,C++11 并未修复它。
std::tm* 指针超过一次格式化调用std::localtime_r(POSIX)或 std::localtime_s(Windows / MSVC)std::chrono::current_zone() 等新接口,但尚未普及,不建议现在强依赖POSIX 下推荐写法:
std::time_t t = std::time(nullptr);
std::tm lt{};
localtime_r(&t, <); // 写入栈上变量 lt,线程安全
std::ostringstream oss;
oss.imbue(std::locale(""));
oss << std::put_time(<, "%F %T");
std::put_time 格式符与平台兼容性大部分格式符跨平台可用,但以下几点容易出错:
%F(等价于 %Y-%m-%d)在旧版 libstdc++(如 GCC 4.9)中不支持,需手动拼接%z 输出时区偏移(如 +0800),但 Windows 默认 locale 下可能输出空;建议用 %Z(时区缩写,如 CST)更稳妥%f(微秒)不是标准 C++,GCC/libstdc++ 支持,MSVC 不支持;高精度应改用 std::chrono + 手动计算"Chinese_China.936",%A/%B 可能输出中文星期/月份,但多数 Linux 发行版 locale 名不含编码后缀(如 zh_CN.UTF-8)真正难的不是写出一行 put_time,而是确保它在不同编译器、不同系统 locale、多线程环境下每次都不崩 —— 很多人卡在 locale 没生效,却去查格式符文档,方向就偏了。