代码之家  ›  专栏  ›  技术社区  ›  Jonathan M Davis

如何在Linux/POSIX中获得任意时区的信息?

  •  2
  • Jonathan M Davis  · 技术社区  · 14 年前

    理想情况下,我希望能够做的是取一个时区的名称并调用一个函数,以在Linux中请求其相应的时区信息(与UTC的偏移量、DST偏移量、DST切换日期等)。然而,我找不到任何方法来做这件事。信息存在于 /usr/share/zoneinfo/

    3 回复  |  直到 12 年前
        1
  •  3
  •   caf    8 年前

    这个 tzcode package (与数据一起在 ftp://ftp.iana.org/tz/releases )包含tzfile格式的描述以及头文件 tzfile.h 直接处理这些数据。

        2
  •  1
  •   Jonathan Leffler    14 年前

    ICU

    • 格式化:根据所选语言环境的约定格式化数字、日期、时间和货币金额。这包括将月份和日期名称转换为所选语言、选择适当的缩写、正确排序字段等。这些数据还来自公共区域设置数据存储库。

    • 时间计算:除了传统的公历之外,还提供了多种类型的日历。 提供了一套完整的时区计算API ( 强调已添加

        3
  •  1
  •   Howard Hinnant    8 年前

    一个老问题的新答案。

    新答案的基本原理:现在有一个 modern, free, open-source, C++11/14/17 library 1 它确实需要 一些 installation full documentation ,甚至是 video introduction .

    下面是一个获取特定时区信息的示例程序。我只是以我自己的时区为例。此库支持完整的 IANA timezone database :

    #include "tz.h"
    #include <iostream>
    
    int
    main()
    {
        auto zone = date::locate_zone("America/New_York");
        std::cout << *zone << '\n';
        std::cout << zone->get_info(std::chrono::system_clock::now()) << '\n';
    }
    

    第一行按其IANA名称查找数据库。

    auto zone = date::locate_zone("America/New_York");
    

    date::time_zone const* nullptr ,但如果找不到时区,它将抛出(具有极好的 what() ).

    std::cout << *zone << '\n';
    

    这一行的输出通常对这个库的客户机没有用处。在调试库时,它主要对我自己有用:

    America/New_York                   -04:56:02                  LMT        1883 Nov/18                  12:03:58         1883-11-18 17:00:00 UTC   1883-11-18 12:03:58 STD   1883-11-18 12:03:58   00:00      {nullptr, -32768}   {nullptr, 32767}
                                       -05:00:00   US             E%sT       1920 Jan/01                  00:00:00         1920-01-01 05:00:00 UTC   1920-01-01 00:00:00 STD   1920-01-01 00:00:00   00:00   S   {US             1918    1919    Mar/Sun[last]           02:00:00       01:00   D, 1918}   {US             1918    1919    Oct/Sun[last]           02:00:00       00:00   S, 1919}
                                       -05:00:00   NYC            E%sT       1942 Jan/01                  00:00:00         1942-01-01 05:00:00 UTC   1942-01-01 00:00:00 STD   1942-01-01 00:00:00   00:00   S   {NYC            1920    1920    Mar/28                  02:00:00       01:00   D, 1920}   {NYC            1921    1954    Sep/Sun[last]           02:00:00       00:00   S, 1941}
                                       -05:00:00   US             E%sT       1946 Jan/01                  00:00:00         1946-01-01 05:00:00 UTC   1946-01-01 00:00:00 STD   1946-01-01 00:00:00   00:00   S   {US             1942    1942    Feb/09                  02:00:00       01:00   W, 1942}   {US             1945    1945    Sep/30                  02:00:00       00:00   S, 1945}
                                       -05:00:00   NYC            E%sT       1967 Jan/01                  00:00:00         1967-01-01 05:00:00 UTC   1967-01-01 00:00:00 STD   1967-01-01 00:00:00   00:00   S   {NYC            1921    1954    Apr/Sun[last]           02:00:00       01:00   D, 1946}   {NYC            1955    1966    Oct/Sun[last]           02:00:00       00:00   S, 1966}
                                       -05:00:00   US             E%sT       32767 Dec/31                  00:00:00UTC      32767-12-31 00:00:00 UTC   32767-12-30 19:00:00 STD   32767-12-30 19:00:00   00:00   S   {US             1967    1973    Apr/Sun[last]           02:00:00       01:00   D, 1967}   {US             2007    32767    Nov/Sun[1]              02:00:00       00:00   S, 32767}
    

    但我展示这一行的原因之一是为了说明询问时区信息,而不同时提供 ,不太可能提供您要查找的信息。关于时区的信息本身就是时间的函数,包括偏移量、夏令时细节、缩写等。

    最后一行:

    std::cout << zone->get_info(std::chrono::system_clock::now()) << '\n';
    

    可能是最有用的。这将返回一个聚合 sys_info 看起来是这样的:

    struct sys_info
    {
        sys_seconds          begin;
        sys_seconds          end;
        std::chrono::seconds offset;
        std::chrono::minutes save;
        std::string          abbrev;
    };
    

    2016-11-06 06:00:00
    2017-03-12 07:00:00
    -05:00:00
    00:00
    EST
    

    • 此信息的有效期为2016-11-06 06:00:00 UTC至(但不包括)2017-03-12 07:00:00 UTC。
    • 这不被视为夏令时(save==00:00)。
    • 这个时期的缩写是EST。

    当然,您可以在程序中访问这个聚合的字段,而不是仅仅打印出来。

    如果您想查看6个月后的结果:

    std::cout << zone->get_info(std::chrono::system_clock::now() + date::months{6}) << '\n';
    

    2017-03-12 07:00:00
    2017-11-05 06:00:00
    -04:00:00
    01:00
    EDT
    

    所有这些都被认为是该库的低级访问。存在更高级别的API,因此您不必处理低级别的概念,例如当前的UTC偏移量。如果您需要的话,底层的东西就在那里(不是隐藏的),但是对于常见的用例(比如获取任何特定时区的当前时间)来说不是必需的:

    using namespace date;
    using namespace std::chrono;
    std::cout << make_zoned("America/New_York", system_clock::now()) << '\n';
    

    对我来说:

    2017-03-07 19:26:53.711662 EST
    

    在C++ 17中,由于模板推导指南,上述行不再需要“制造工厂函数”用于演绎目的:

    std::cout << zoned_time{"America/New_York", system_clock::now()} << '\n';
    

    zoned_time 是一个类模板,以持续时间为模板,由 chrono::duration chrono::time_point (第二个论点——在我的例子中) microseconds ).

    这是一个具有低级别访问和高层次抽象的完整功能的日期/时间/时区库(对C++的哲学是正确的)。正确性和类型安全性在这个库中受到高度重视。它是一个 <chrono> 在C++ 11中引入了库。


    1 免责声明:我是这个图书馆的主要作者,尽管有很多贡献者(对此我很感激)。

    推荐文章