2010-09-09 39 views
2

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

回答

1

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

  • 格式:根据所选语言环境的约定格式化数字,日期,时间和货币金额。这包括将月份和日期名称翻译成所选语言,选择适当的缩写,正确排序字段等。此数据也来自Common Locale Data Repository。

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

+0

ICU确实有适当的日历实施./ – 2012-10-11 17:18:54

1

旧问题的新答案。

新答案的依据:现在有一个modern, free, open-source, C++11/14/17 library可以做到这一点。 它确实需要一些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月6日06 :00:00 UTC直到(但不包括)2017-03-12 07:00:00 UTC。
  • 此时间段的UTC偏移量为-5小时。
  • 这不被视为夏令时期(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::time_point(第二个参数 - 在本例中为microseconds)的chrono::duration推导出来。

这是一个全功能的日期/时间/时区库,既有低级访问,也有高级抽象(正如C++的哲学)。正确性和类型安全性在这个图书馆中是非常重要的。它是C++ 11中引入的<chrono>库的扩展,不是替代品。


免责声明:我是这个库的主要作者,虽然有很多的贡献者(对此我很感激)。