使用Howard Hinnant日期库处理时区/DST无效时间转换出错求助
问题原因与解决方案
核心原因
2023年3月12日凌晨2:00:00是America/New_York时区夏令时切换的无效时间点:此时区会从EST(东部标准时间,UTC-5)直接跳转到EDT(东部夏令时,UTC-4),时钟从1:59:59直接跳到3:00:00,所以2:00:00这个本地时间根本不存在。date库抛出date::nonexistent_local_time是正常的预期行为,用于提示你处理无效时间。
解决办法
1. 捕获异常并手动修正时间
如果业务逻辑允许自动调整,可以捕获异常后将时间修正为切换后的3:00:00,示例代码:
#include "date/tz.h" #include <iostream> #include <stdexcept> int main() { using namespace date; using namespace std::chrono; // 指向你的tzdata存放路径 std::setenv("TZDIR", "/c/Users/你的用户名/Downloads/tzdata", 1); try { local_days ld = 2023_y/march/12; auto lt = ld + 2h + 0min + 0s; zoned_time<system_clock::duration> zt{"America/New_York", lt}; std::cout << zt << '\n'; } catch (const nonexistent_local_time& e) { // 自动修正为夏令时切换后的时间 auto corrected_lt = e.end; zoned_time<system_clock::duration> zt{"America/New_York", corrected_lt}; std::cout << "修正后的时间:" << zt << '\n'; } return 0; }
2. 使用宽松转换策略
date库支持通过choose标签指定转换规则,直接跳过无效时间间隙,自动映射到合法时间:
#include "date/tz.h" #include <iostream> int main() { using namespace date; using namespace std::chrono; std::setenv("TZDIR", "/c/Users/你的用户名/Downloads/tzdata", 1); local_days ld = 2023_y/march/12; auto lt = ld + 2h + 0min + 0s; // 用choose::latest将无效时间映射到间隙结束的3:00:00 EDT zoned_time<system_clock::duration> zt{"America/New_York", choose::latest, lt}; std::cout << zt << '\n'; return 0; }
choose可选策略:
choose::earliest:将无效时间映射到间隙开始的1:59:59 ESTchoose::latest:映射到间隙结束的3:00:00 EDT
3. 确保时区数据正确加载
你将tzdata放在Downloads文件夹,需要让程序能找到它:
- 终端运行前设置环境变量:
export TZDIR="/c/Users/你的用户名/Downloads/tzdata" ./你的程序.exe - 或者在代码中通过
std::setenv指定路径(如上述示例) - 也可以将tzdata复制到MSYS2默认时区路径
/usr/share/zoneinfo,无需额外设置
编译注意事项
使用mingw编译时,需要链接tz库,示例命令:
g++ -std=c++20 your_code.cpp -o your_program.exe -ltz -I/path/to/date/include
替换/path/to/date/include为你date库头文件的实际路径
内容的提问来源于stack exchange,提问作者tech1978
相关产品推荐
相关产品推荐

