std::put_time在Windows上对非"C" locale支持极弱,跨平台最稳方案是手写中文月份映射表配合std::chrono获取1–12月份数值查表;需注意month为1-based、避免宽字符转换陷阱及农历语境混淆。

用 std::put_time 配合 locale 获取中文月份名失败的原因
直接用 std::put_time + "%B" 并设置中文 locale(如 "zh_CN.UTF-8")在多数 Linux/macOS 环境下能工作,但在 Windows 上基本无效——MSVC 的 C++ 标准库对非 "C" locale 的 std::put_time 支持极弱,甚至会崩溃或返回空字符串。Clang/GCC 也依赖系统 locale 数据是否完整,不是所有发行版默认装了中文翻译。
跨平台最稳的方式:手写映射表 + std::chrono
绕过 locale 依赖,用 std::chrono::system_clock 获取当前时间,再提取月份(1–12),查表返回中文名。简单、可控、无外部依赖。
实操建议:
- 月份从
std::chrono::year_month_day中取:ymd.month().operator int()返回 1–12(不是 0–11) - 用
std::array或constexpr std::string_view存储,避免运行时构造开销 - 注意:C++20 起
std::chrono::current_zone()不可用,别想用时区名推语言;老版本更得靠查表
constexpr std::array<std::string_view, 12> kMonthNames = {
"一月", "二月", "三月", "四月", "五月", "六月",
"七月", "八月", "九月", "十月", "十一月", "十二月"
};
<p>auto now = std::chrono::system_clock::now();
auto ymd = std::chrono::year_month_day{std::chrono::floor<std::chrono::days>(now)};
int month = static_cast<int>(ymd.month());
std::string cn_name = std::string(kMonthNames[month - 1]); // month 是 1-based
如果坚持用 locale,必须检查系统支持
仅限 Linux/macOS 测试环境,且需确认 locale 实际存在:
立即学习“C++免费学习笔记(深入)”;
- 终端执行
locale -a | grep "zh_CN",确保输出含zh_CN.utf8或类似项 - C++ 中设 locale 前加判断:
try { std::locale("zh_CN.UTF-8"); } catch(...) { /* fallback */ } - 即使设成功,
std::put_time在 GCC 12+ 之前对宽字符支持不全,建议统一用窄字符 + UTF-8 编码输出
Windows 下用 GetLocaleInfoEx 是唯一可靠原生方案
Win32 API 提供稳定中文月份名,但需手动转码(返回的是 UTF-16):
- 调用
GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SMONTHNAME1 + month - 1, ...) - month 仍为 1–12;
LOCALE_SMONTHNAME1是一月,LOCALE_SMONTHNAME12是十二月 - 结果是
wchar_t*,需用std::wstring_convert<std::codecvt_utf8<wchar_t>>或 C++11 后推荐的std::wcstombs转 UTF-8 - 注意:VC++2015+ 已弃用
std::wstring_convert,稳妥做法是用WideCharToMultiByte(CP_UTF8, ...)
Windows 的 API 调用路径和 Linux 的 locale 行为差异太大,真要写跨平台代码,查表仍是首选。很多人忽略的是:月份名本身有语境差异——比如“正月”在农历里特指一月,但公历场景下一律用“一月”,查表时别混入农历逻辑。


















