计时解析包括时区

chrono parse including timezone

我正在使用@howard-hinnant 的日期库(现在是 C++20 的一部分)来解析包含时区缩写的日期字符串。解析没有错误,但时区似乎被忽略了。例如:

        istringstream inEst{"Fri, 25 Sep 2020 13:44:43 EST"};
        std::chrono::time_point<std::chrono::system_clock, chrono::seconds> tpEst;
        inEst >> date::parse("%a, %d %b %Y %T %Z", tpEst);
        std::cout <<  chrono::duration_cast<chrono::milliseconds>( tpEst.time_since_epoch() ).count() << std::endl;

        istringstream inPst{"Fri, 25 Sep 2020 13:44:43 PST"};
        std::chrono::time_point<std::chrono::system_clock, chrono::seconds> tpPst;
        inPst >> date::parse("%a, %d %b %Y %T %Z", tpPst);
        std::cout <<  chrono::duration_cast<chrono::milliseconds>( tpPst.time_since_epoch() ).count() << std::endl;

        istringstream inGmt{"Fri, 25 Sep 2020 13:44:43 GMT"};
        std::chrono::time_point<std::chrono::system_clock, chrono::seconds> tpGmt;
        inGmt >> date::parse("%a, %d %b %Y %T %Z", tpGmt);
        std::cout <<  chrono::duration_cast<chrono::milliseconds>( tpGmt.time_since_epoch() ).count() << std::endl;

产生输出:

1601041483000
1601041483000
1601041483000

是我做错了什么,还是解析器没有使用时区信息?

遗憾的是,仅给定时区缩写,无法可靠且唯一地标识时区。一些缩写被多个时区使用,有时甚至具有不同的 UTC 偏移量。

简而言之,时区 缩写 被解析,但未识别可用于更改已解析时间戳的 UTC 偏移量。

请参阅 Convert a time zone abbreviation into a time zone 以获取尝试至少缩小哪些时区同时使用特定时区缩写的代码。

或者,如果您解析 UTC 偏移量("%z""%Ez"),则该偏移量 应用于时间戳以将其转换sys_time.


Fwiw,我 运行 这三个示例中的每一个都通过 find_by_abbrev 重载 local_time 描述 here。结果很有趣,因为它们可能证实了解析时区缩写的脆弱性:

"Fri, 25 Sep 2020 13:44:43 EST"

可能是以下任何时区:

2020-09-25 13:44:43 EST 2020-09-25 18:44:43 UTC America/Atikokan 
2020-09-25 13:44:43 EST 2020-09-25 18:44:43 UTC America/Cancun 
2020-09-25 13:44:43 EST 2020-09-25 18:44:43 UTC America/Jamaica 
2020-09-25 13:44:43 EST 2020-09-25 18:44:43 UTC America/Panama 
2020-09-25 13:44:43 EST 2020-09-25 18:44:43 UTC EST 

所有这些都具有 -5h 的 UTC 偏移量。因此,从这个意义上说,UTC 等效值是唯一的(2020-09-25 18:44:43 UTC,如上所示)。然而,人们不得不怀疑 America/Montreal 是否真的是有意的,它在这个日期的 UTC 偏移量为 -4h 和 EDT 的缩写。

"Fri, 25 Sep 2020 13:44:43 PST"

只有一场比赛!

2020-09-25 13:44:43 PST 2020-09-25 05:44:43 UTC Asia/Manila

这具有 8 小时的 UTC 偏移量。但是我想知道 America/Vancouver 是否是有意的,它在这个日期的 UTC 偏移量为 -7h 和 PDT 的缩写。

如果知道要解析的缩写的匹配 UTC 偏移量,则可以解析为 local_time,解析缩写,查找 UTC 偏移量,并将其应用于 t运行将 local_time 变成 sys_time。这个库可以很容易地解析缩写和时间戳:

local_seconds tpEst;
std::string abbrev;
inEst >> date::parse("%a, %d %b %Y %T %Z", tpEst, abbrev);
sys_seconds tpUTC{tpEst - local_seconds{} - get_offset(abbrev)};

其中 get_offset(abbrev) 是您写入的自定义地图 return 给定时区缩写的偏移量。请注意,如果(例如)打算使用 EDT (-4h) 但解析了 EST (-5h),这将无济于事。

另一种可能的策略是将缩写映射到时区名称(而不是偏移量)。例如:“EST”和“EDT”都可以映射到“America/Toronto”,然后你可以这样做:

local_seconds tpEst;
std::string abbrev;
inEst >> date::parse("%a, %d %b %Y %T %Z", tpEst, abbrev);
zoned_seconds zt{get_tz_name(abbrev), tpEst};
sys_seconds tpUTC = zt.get_sys_time();