使用 Howard Hinnant 的库使用时区名称解析 date/time 时出现问题

Problem parsing date/time with timezone name using Howard Hinnant's library

我正在编写一种方法来解析 date/time 多种格式的字符串。

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 UST。另外两个是 18:17:00 UST。工作得很好。为了简洁起见,我省略了所有这些代码。这是行不通的:

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

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

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

我不确定我做错了什么。

当读取带有%z(例如-0600)的偏移量时,结合sys_time类型(例如system_clock::time_point),解析时间点被解释为本地时间,并根据前两个示例中的需要应用偏移量来获得 sys_time

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

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

然而一切并没有丢失。您可以将带有 %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

这与 -6h 偏移相差一个小时,因为 US/Central 在 2022-03-13(-5h 偏移)进入夏令时。