我正在使用 @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,我通过采用 local_time
描述的 find_by_abbrev
重载来运行这三个示例 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
所有这些的 UTC 偏移量均为 -5h。因此从这个意义上说,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
UTC 偏移量为 8 小时。但我不得不怀疑 America/Vancouver 是否是有意为之,该日期的 UTC 偏移量为 -7h,并且是 PDT 的缩写。
如果知道要解析的缩写的匹配 UTC 偏移量,则可以解析为 local_time
,解析缩写,查找 UTC 偏移量,并将其应用于转换 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)
是您编写的自定义 map ,用于返回给定时区缩写的偏移量。请注意,如果(例如)预期是 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();
关于c++ - 包括时区的 chrono 解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64066275/