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

发布于 2025-01-16 02:07:15 字数 1086 浏览 0 评论 0原文

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

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

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

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

我不确定我做错了什么。

I'm writing a method to parse date/time strings in a variety of formats.

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;
}

I then test it with a variety of inputs. The other formats work. I can do these:

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

The latter two are for US Mountain Daylight Time. It does all the right things. The first one shows as 12:17:00 UST. The other two are 18:17:00 UST. Working great. I've omitted all that code for brevity. What does not work is this:

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

I've tried a variety of timezone names after writing a different program to dump the ones known by Howard's library. None of them matter. I get a UST-time value with no time zone offset.

Luckily, what I need right now is the -06:00 format, so I can move forward. But I'd like to fix the code, as we have other places that use timezone names, and I'd like to get this working properly.

I'm not sure what I'm doing wrong.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

玉环 2025-01-23 02:07:15

当使用 %z(例如 -0600)读取偏移量时,结合 sys_time 类型(例如 system_clock::time_point) code>,解析时间点被解释为本地时间,并且应用偏移量来获取 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 年 3 月 13 日(-5 小时偏移量)进入夏令时。

When reading an offset with %z (e.g. -0600), combined with a sys_time type such as system_clock::time_point, the parse time point is interpreted as a local time, and the offset is applied to get the sys_time, as desired in your first two examples.

However this is not the case when reading a time zone name or abbreviation with %Z (note the change from lower case z to upper case Z).

%Z parses a time zone abbreviation or name, which is just a string. The common case is for this to just parse an abbreviation, e.g. CST. And in general, there is no unique mapping from an abbreviation to an offset. And so the offset can not be internally applied. Thus the parsed value should always be interpreted as a local time.

However all is not lost. You can parse the time zone name with %Z into a string, and then look up the time_zone with that name and use it to convert the parse local_time into a sys_time. This could look like:

#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';
}

Just add a string as the third argument in your parse call, and make sure the first argument is a local_time instead of a sys_time. Then use locate_zone to get a time_zone const* and call to_sys with that, passing in the parsed local_time.

The above program outputs:

2022-04-01 17:17:00.123400

This is an hour off from the -6h offset because US/Central goes to daylight saving on 2022-03-13 (-5h offset).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文