MSVC2022+Windows11下用std::chrono获取America/Montreal时区遇异常
解决方案:封装安全的时区信息获取函数
首先要明确:locate_zone返回非空指针只能说明该时区在数据库中存在,但不代表调用get_info时不会因为ICU数据或MSVC实现的问题抛出异常——这也是你当前空判断无效的原因。
目前MSVC的std::chrono时区模块没有提供直接的预检查API来判断某个时间点是否能安全获取时区信息,最务实的方案是把try/catch封装成一个工具函数,对外提供类似预检查的接口:
#include <chrono> #include <optional> std::optional<std::chrono::sys_info> safe_get_timezone_info(const std::chrono::time_zone* zone, std::chrono::sys_days date) { if (!zone) return std::nullopt; try { return zone->get_info(date); } catch (...) { // 捕获所有时区相关异常,返回空值表示获取失败 return std::nullopt; } }
然后修改你的测试代码,用这个函数替代直接调用get_info,就能用if判断结果是否有效:
#include <chrono> #include <optional> // 上面的safe_get_timezone_info函数放在这里 int main(int, char**) { using namespace std::chrono; auto z = get_tzdb().locate_zone("America/Montreal"); auto QuebecDay = 2023y / 6 / 24; auto info_opt = safe_get_timezone_info(z, sys_days(QuebecDay)); if (info_opt) { // 成功获取时区信息,使用info_opt.value()访问 auto info = *info_opt; // 后续逻辑... } else { // 处理获取失败的情况 } return 0; }
额外说明
- 你使用的ICU版本仍存在该问题,说明这可能是MSVC对ICU数据的适配bug,而非ICU本身的问题。可以尝试更新到最新的MSVC 2022版本(比如17.8及以上),微软可能在后续补丁中修复这类特定时区的异常问题。
- 如果需要批量预检查多个时区或时间点,可以在程序启动时提前调用
safe_get_timezone_info做一次预校验,把可用的时区/时间点缓存起来,避免运行时重复捕获异常。
内容的提问来源于stack exchange,提问作者Daniel Anderson
相关产品推荐
相关产品推荐

