计时解析包括时区
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();
我正在使用@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();