mktime不能直接解析字符串,必须先用strptime(Linux/macOS)或std::get_time(Windows/C++11)将字符串填入已清零的struct tm,再调用mktime转为time_t。

用 strptime 解析字符串到 struct tm,再转 time_t
标准 C++ 没有直接解析日期字符串的函数,得靠 C 标准库的 strptime(POSIX)先把字符串填进 struct tm,再用 mktime 转成 time_t。注意:strptime 不是 ISO C 标准函数,在 Windows 上默认不可用(MSVC 不提供),需换方案或启用兼容层。
常见错误:直接用 sscanf 手动拆分但忽略 tm 字段的取值范围(比如 tm_mon 是 0–11,tm_year 是距 1900 年的偏移),导致 mktime 返回 -1。
-
strptime的格式串必须严格匹配输入,比如"%Y-%m-%d"对应"2023-10-25";多空格、多余字符都会失败 - 调用前必须把
struct tm初始化为 0(尤其tm_isdst,否则mktime可能按本地规则误判夏令时) - 解析后要检查返回值是否为
nullptr,否则mktime输入的是未定义状态
Windows 下替代方案:用 std::get_time + mktime
Windows 编译器(如 MSVC)不支持 strptime,但 C++11 起的 std::get_time 可以在 std::istringstream 中完成类似解析,且跨平台兼容性更好。
容易踩的坑:必须在流上设置 std::locale(默认 locale 可能不识别 %Y 等格式),且 std::get_time 不会自动清零 struct tm —— 忘记初始化仍会导致 mktime 行为异常。
立即学习“C++免费学习笔记(深入)”;
- 务必用
std::memset(&tm, 0, sizeof(tm))或struct tm tm{};初始化 - 流操作后检查
iss.fail(),不能只看iss.eof() -
std::get_time不支持毫秒、时区等扩展格式,纯日期够用,带时间需额外处理
mktime 返回 -1 怎么排查
mktime 返回 -1 表示输入的 struct tm 无效,不是“解析失败”的信号——它发生在解析之后。最常被忽略的原因是字段越界或未初始化。
-
tm_mon写成 10(表示十月)是对的,但若误写成 10+1 就越界;tm_mday不能为 0 -
tm_year必须是 123 表示 2023 年(即 2023−1900),写成 2023 直接溢出 - 即使日期合法,若系统时区数据库损坏或
tzset()未调用(极少见),也可能影响结果
C++20 std::chrono::parse 是更现代的选择
如果你能用 C++20,std::chrono::parse 配合 std::chrono::sys_days 是类型安全、无需手动管理 struct tm 的方案,底层自动处理时区和闰年。
但它不直接产出 time_t,需要再转一次:std::chrono::system_clock::to_time_t。而且目前部分标准库实现(如 libstdc++ 12 前)对 parse 支持不完整,编译可能报错 no matching function。
- 确保编译器开启
-std=c++20且标准库较新(GCC 13+/Clang 15+/MSVC 19.32+) - 格式字符串用
"%F"(等价于"%Y-%m-%d")最稳妥,避免手写"%Y-%m-%d"时漏掉终止符 - 返回的是
std::chrono::sys_days,别忘了调用.time_since_epoch().count()或直接转time_t
std::get_time 是目前最平衡的选择;如果只跑 Linux,strptime 更轻量;C++20 方案清晰但要注意工具链水位——很多遗留构建环境还没跟上。


















