std::put_time 是函数模板,不能直接传入裸字符串或c风格时间结构,必须配合 std::time_put facet 使用,而标准流默认不支持。

std::put_time 编译失败:missing template arguments?
根本原因是 std::put_time 是函数模板,不能直接传入裸字符串或 C 风格时间结构。它必须配合 std::time_put facet 使用,而标准流默认不支持——所以你写 std::cout 却报错,大概率是漏了 <code>std::locale 设置。
- 必须先为输出流 imbue 一个带
std::time_put的 locale,比如std::cout.imbue(std::locale(""));(依赖系统 locale) - 更稳妥的做法是显式构造 facet:
std::use_facet<:time_put>>(std::locale())</:time_put>,但日常用不到 - 常见错误现象:
error: no matching function for call to 'put_time'或模板推导失败,本质是编译器没看到可用的time_put实例 - Windows 下若未设置环境 locale(如未调用
setlocale(LC_ALL, "")),std::locale("")可能 fallback 到 "C",导致put_time输出空或异常
std::put_time 格式符不生效:%Y、%H 全变成字面量?
格式字符串必须是宽字符字面量(L"...")且与流类型严格匹配:std::wcout 配 std::put_time<wchar_t></wchar_t>,std::cout 配 std::put_time<char></char>。混用会导致格式符被原样输出,不解析。
- 用
std::cout时,格式串必须是"%Y-%m-%d %H:%M"(窄字符),不是L"%Y..." - 用
std::wcout时,格式串必须是L"%Y-%m-%d %H:%M",且需确保流已 imbue 支持宽字符的 locale - Linux/macOS 一般没问题;Windows 控制台默认不支持 UTF-8 宽字符输出,
wcout可能乱码或静默失败 - 别用
std::string构造格式串再传给put_time——它只接受 C 风格字符串字面量或std::basic_string::c_str(),且生命周期必须长于流操作
替代方案:为什么很多人绕过 std::put_time 直接用 strftime?
std::put_time 看似高级,但实际约束多、可移植性差;而 std::strftime 是 C 标准函数,参数明确、行为稳定,配合 std::put_time 的底层逻辑几乎一致,只是少了流集成。
-
strftime接收char*缓冲区,需手动管理大小,容易溢出——务必用std::vector<char>(256)</char>预分配,再传.data() - 它不依赖 locale 设置,
%Z、%z等时区字段在多数平台更可靠 - C++20 引入
<chrono></chrono>的std::format(如std::format("{:%Y-%m-%d}", tp)),但目前 MSVC/GCC 支持不一,生产环境慎用 - 简单场景示例:
char buf[64];<br>strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", std::localtime(&t));<br>std::cout << buf;
std::put_time 性能和线程安全要注意什么?
它本身是无状态的,但依赖的 std::time_put facet 是 locale 的一部分,而 locale 对象在不同线程间共享时,若被并发修改(比如某处调用了 std::locale::global()),可能引发未定义行为。
立即学习“C++免费学习笔记(深入)”;
- 不要在多线程中全局切换 locale;每个线程应使用独立的 imbued 流,或干脆避免
put_time,改用线程安全的strftime -
put_time每次调用都会触发 facet 查找,比直接调用strftime多一次虚函数调用开销,高频日志场景有感知 - Android NDK 或嵌入式 libc(如 newlib)可能未完全实现
time_put,put_time会返回空字符串——这种环境下必须降级到strftime










