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

时间:2010-09-09 03:34:02

标签: c++ c linux timezone posix

理想情况下,我希望能够做的是获取时区的名称并调用函数来询问其相应的时区信息(偏离UTC,DST偏移,DST开关的日期等)。 )在Linux中。但是,我找不到任何方法来做到这一点。信息存在于/usr/share/zoneinfo/的各种二进制文件中,但我不知道如何阅读它们,或者是否有办法让操作系统向您提供信息,而不是必须在你自己。所以,我正在寻找获取这些信息的方法。理想情况下,会有一个posix函数可以为你做到这样它可以在Linux以外的POSIX系统上运行,但如果没有,我至少想知道正确的方法(或者至少是最好的方式)方式)获取Linux中任意时区的时区信息。

3 个答案:

答案 0 :(得分:3)

tzcode package(与ftp://ftp.iana.org/tz/releases处的数据一起找到)包含tzfile格式的描述以及用于直接处理该数据的头文件tzfile.h

答案 1 :(得分:1)

没有标准的方法可以做到这一点。你可以看看ICU。它声称:

  • 格式设置:根据所选区域设置的惯例格式化数字,日期,时间和货币金额。这包括将月和日名称转换为所选语言,选择适当的缩写,正确排序字段等。此数据也来自Common Locale Data Repository。

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

答案 2 :(得分:1)

旧问题的新答案。

新答案的基本原理:现在有modern, free, open-source, C++11/14/17 library来执行此操作。 1 确实需要一些 installation。但它可以在Linux / macOS / Windows上移植。它有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。
  • 此时间段的UTC偏移量为-5小时。
  • 这不被视为夏令时(保存== 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)。< / p>

这是一个功能齐全的日期/时间/时区库,具有低级访问和高级抽象(符合C ++的理念)。这个图书馆非常重视正确性和类型安全性。它是扩展,而不是C ++ 11中引入的<chrono>库的替代。

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