2012-12-12 78 views

回答

21

不幸的是PostgreSQL並不提供一個時區的數據類型,所以你應該使用text

interval乍一看似乎是一個合乎邏輯的選項,它的適合某些用途。但是,它不考慮夏令時,也不考慮同一UTC偏移中的不同地區具有不同DST規則的事實。

從UTC偏移到時區沒有1:1的映射。

例如,對於Australia/Sydney時區(新南威爾士州)是UTC+10在夏令時(EST),或UTC+11EDT)。是的,這是美國使用的縮寫EST;時區首字母縮寫詞在tzdata數據庫中不是唯一的,這就是Pg具有timezone_abbreviations設置的原因。更糟糕的是,布里斯班(昆士蘭州)的經濟狀況幾乎相同,在UTC+10 EST ...但沒有夏令時,所以在新南威爾士州夏令時期間,它的偏移量爲-1

更新:最近,澳大利亞通過了一項A前綴,所以它使用AEST作爲其東部各州TZ縮寫,但ESTWST仍然普遍使用)。

混淆不清?

如果您只需要存儲一個UTC偏移量那麼interval是合適的。如果要存儲時區,請將其存儲爲text。現在驗證並轉換爲時區偏移是一種痛苦,但至少它應對了DST。

+1

是否有指向所有時區的規範文本字符串(澳大利亞/悉尼)的鏈接? – odigity

+1

是的:http://en.wikipedia.org/wiki/List_of_tz_database_time_zones – odigity

+0

如果你想優化性能+節省空間(並降低可移植性/靈活性),tz數據庫+枚舉將是很好的 –

1

也許間隔

 
postgres=# select interval '01:30'; 
interval 
---------- 
01:30:00 
(1 row) 

postgres=# select interval '-01:30'; 
interval 
----------- 
-01:30:00 
(1 row) 
9

「+ hh:mm」和「-hh:mm」不是時區,它們是UTC偏移量。一個好的格式來保存這些數據是一個有符號整數,偏移量以分鐘爲單位。你也可以使用像interval這樣的東西,但這隻會幫助你,如果你想直接在PostgreSQL中進行日期計算,就像在查詢中一樣,通常你可以用另一種語言來做這些計算,然後它依賴於那種語言支持interval類型,並具有良好的日期/時間庫或不。但是將整數轉換成類似於interval類型的類型,如Pythons timedelta應該是微不足道的,所以我個人將其作爲整數存儲。

時區有名稱,儘管沒有時區的標準化名稱,但在「tz」或「zoneinfo」數據庫中有一個事實標準,例如「Europe/Paris」,「Americas/New_York「或」US/Pacific「。這些應該存儲爲字符串。

Windows使用完全不同的名稱,如「浪漫時間」(不問)。你可以將它們和字符串一起存儲,但是我會避免它,這些名稱不能在Windows之外使用,並且名稱沒有意義。此外,Windows的翻譯版本傾向於爲這些時區使用翻譯後的名稱,使其更加糟糕。

像「PDT」和「EST」這樣的縮寫不能用作時區名稱,因爲它們不是唯一的。有四種(我認爲還是五種?)不同的時區都稱爲「CST」,所以這是不可用的。

總之:對於時區,將名稱存儲爲字符串。對於UTC偏移量,以分鐘爲單位將偏移量存儲爲有符號整數。

+0

是否有鏈接到規範文本字符串(澳大利亞/悉尼)的所有時區? – odigity

+0

是的:http://en.wikipedia.org/wiki/List_of_tz_database_time_zones – odigity

4

在一個理想的世界中,您可以擁有一組已知時區的外鍵。你可以通過視圖和域來做到這一點。

wiki tip由David E. Wheleer創建了其有效性測試作爲一個時區域:

CREATE OR REPLACE FUNCTION is_timezone(tz TEXT) RETURNS BOOLEAN as $$ 
BEGIN 
PERFORM now() AT TIME ZONE tz; 
RETURN TRUE; 
EXCEPTION WHEN invalid_parameter_value THEN 
RETURN FALSE; 
END; 
$$ language plpgsql STABLE; 

CREATE DOMAIN timezone AS CITEXT 
CHECK (is_timezone(value)); 

這是非常有用的已知時區的列表,在這種情況下,你可以在域名分配和剛剛執行在所述一個表包含已知的時區的名稱(從視圖pg_timezone_names)中獲得的約束,避免需要暴露別處域:

CREATE TABLE tzone 
(
    tzone_name text PRIMARY KEY (tzone_name) CHECK (is_timezone(tzone_name)) 
); 

INSERT INTO tzone (tzone_name) 
SELECT name FROM pg_timezone_names; 

然後就可以通過執行forei正確性gn鍵:

CREATE TABLE myTable (
... 
tzone TEXT REFERENCES tzone(tzone_name) 
); 
相關問題