2010-09-09 306 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>庫的擴展,不是替代品。


免責聲明:我是這個庫的主要作者,雖然有很多的貢獻者(對此我很感激)。