std::get_time解析英文月份需设c locale,否则静默失败;推荐手动查表映射缩写,避免locale依赖;c++20 std::chrono::parse仍受locale限制;注意时区、dst及时间精度问题。

用 std::get_time 解析带英文月份的日期字符串
标准库不支持直接识别 "Oct" 这类缩写月份,必须配合 std::locale 设置 C locale(非系统默认 locale),否则 std::get_time 会静默失败或解析出错。
常见错误现象:解析后 tm.tm_mon 是 -1,或整个流状态为 failbit,但没报异常——因为 std::get_time 是格式化输入,失败时不抛异常,只置标志位。
- 必须在解析前调用
std::cin.imbue(std::locale("C"))(或对任意std::istringstream做同样设置) - 格式字符串严格对应:年月日顺序、分隔符、大小写——
"%Y-%b-%d"中%b才认英文缩写,%B是全称,%m是数字月份 - 输入字符串末尾不能有多余空格或换行,否则
ss >> std::get_time(...)可能卡在尾部匹配上
手动映射月份缩写更可控
当项目不允许依赖 locale(比如嵌入式、多线程环境 locale 切换不安全),或需要兼容非 C locale 系统(如某些 Android NDK 版本),建议跳过 std::get_time,改用字符串切分 + 查表。
示例逻辑:按 '-' 拆成三段 → 第二段查 std::unordered_map<:string int></:string> 得到月份序号("Oct" → 9)→ 转成 std::tm 结构体。
- 查表 key 全小写或全大写,避免大小写敏感问题;
"oct"、"OCT"都转小写再查 - 注意
std::tm::tm_mon是 0 起始(0=Jan),别漏减 1 - 年份字段要检查是否为 4 位数字,避免把
"23"当 1923 或 2023 —— 原始字符串是"2023-Oct-25",所以直接std::stoi即可
std::chrono::parse(C++20)不是万能解
C++20 引入了 std::chrono::parse,但它对 %b 的支持仍依赖底层 locale,和 std::get_time 行为一致。也就是说,不设 C locale,parse 同样无法识别 "Oct"。
而且目前主流编译器(GCC 13/Clang 16)对 std::chrono::parse 的 %b 实现仍不完整,部分平台返回 std::errc::invalid_argument。
- 若已用 C++20,优先走手动查表 +
std::chrono::system_clock::from_time_t转换 - 不要假设
parse自动跨 locale 工作;它只是语法糖,底层仍是 locale 绑定的std::get_time - 时间精度注意:原始字符串无时分秒,默认为当天 00:00:00,
std::tm初始化时需显式设tm.tm_hour = tm.tm_min = tm.tm_sec = 0
时区与 DST 是最容易被忽略的坑
所有上述方法都产出本地时间的 std::tm,但没指定时区。如果后续要转成 std::time_t 或 std::chrono::system_clock::time_point,mktime 会按当前程序时区解释这个时间——哪怕输入是 UTC 时间,也会被当成本地时间处理。
例如:服务器在东八区,你解析 "2023-Oct-25" 得到 tm,调用 mktime(&tm),结果对应的是北京时间 2023-10-25 00:00:00,而非 UTC 时间。
- 若输入明确是 UTC,用
timegm(POSIX)或_mkgmtime(MSVC)代替mktime - 跨平台项目中,
timegm不是标准函数,需条件编译或自己实现简易版(基于std::chrono+ 固定时区偏移) - DST 变更日(如 10 月最后一个周日)附近,
mktime可能因夏令时切换导致时间偏移 1 小时,务必验证边界日期
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











