c++ - 包括时区的 chrono 解析

标签 c++ c++-chrono date-parsing datetime-parsing

我正在使用 @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/

相关文章:

c++ - 隐式 move 构造函数和赋值运算符

c++ - 无法理解类型别名和常量

c++ - 日期时间到 UTC

java - 使用 Joda Time 解析 Twitter 日期

python - 在 re.sub 中使用变量,用于 Python 解析多个日期时间格式的字符串?

c++ - GDB 如何处理 SIGSEGV

c++ - 关于将临时对象传递给 const 引用

jquery - 将时间附加到 JQuery 日期选择器?

c++ - 与 `std::chrono` 类型相比,为什么使用 `float` 进行时差测量会给出更多有效数字的 `double` 类型?

c++ - 使用 Howard Hinnant 的库解析带有时区名称的日期/时间时出现问题