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



我正在编写一个方法来解析各种格式的日期/时间字符串。

std::chrono::system_clock::time_point toTimePoint(const std::string str) {
... a bunch of code that determines the format of the input string
std::string formatStr = string{"%Y-%m-%d"}
+ " "       // Delimeter between date and time.
+ "%H:%M:%S"
+ "%t%Z"
;
// The %t should be 0 or 1 whitespace
// The %Z should be a timezone name
std::chrono::system_clock::time_point retVal;
std::istringstream in{str};
in >> date::parse(formatStr, retVal);
return retVal;
}

然后我用各种输入进行测试。其他格式也可以。我可以做这些:

2022-04-01 12:17:00.1234
2022-04-01 12:17:00.1234-0600
2022-04-01 12:17:00.1234-06:00

后两者适用于美国山地夏令时。它做了所有正确的事情。第一个显示为美国东部时间12:17:00。另外两个时间是美国东部时间18:17:00。工作很棒。为了简洁起见,我省略了所有的代码。不起作用的是:

2022-04-01 12:17:00.1234 US/Central

在编写了一个不同的程序来转储霍华德图书馆已知的时区名称后,我尝试了各种时区名称。它们都无关紧要。我得到一个没有时区偏移的UST时间值。

幸运的是,我现在需要的是-06:00格式,这样我就可以继续前进了。但我想修复代码,因为我们还有其他使用时区名称的地方,我想让它正常工作。

我不确定我做错了什么。

当使用%z(例如-0600(读取偏移量,并与sys_time类型(如system_clock::time_point(组合时,解析时间点被解释为本地时间,并应用偏移量来获得sys_time,如前两个示例中所需。

然而,当用%Z读取时区名称或缩写时,情况并非如此(注意从小写z变为大写z(。

%Z解析时区缩写或名称,它只是一个字符串。常见的情况是,这只是解析一个缩写,例如CST。一般来说,从缩写到偏移没有唯一的映射。因此不能在内部应用偏移。因此,解析后的值应始终被解释为本地时间。

然而,并没有失去一切。您可以将具有%Z的时区名称解析为字符串,然后查找具有该名称的time_zone,并使用它将解析的local_time转换为sys_time。这可能看起来像:

#include "date/tz.h"
#include <chrono>
#include <iostream>
#include <sstream>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
istringstream in{"2022-04-01 12:17:00.1234 US/Central"};
string tz_name;
local_time<microseconds> local_tp;
in >> parse("%F %T%t%Z", local_tp, tz_name);
system_clock::time_point tp = locate_zone(tz_name)->to_sys(local_tp);
cout << tp << 'n';
}

只需在parse调用中添加一个string作为第三个参数,并确保第一个参数是local_time而不是sys_time。然后使用locate_zone获得一个time_zone const*,并用它调用to_sys,传入解析后的local_time

上述程序输出:

2022-04-01 17:17:00.123400

这距离-6小时的偏移量还有一个小时,因为美国/中部在2022-03-13(-5小时偏移量(进入夏令时。

最新更新