2013-09-28 110 views
3

我有一個沒有時區的時間戳表。 YYYY-MM-DD HH:MM:SSPostgresql:如何從時間戳,時區字段正確創建帶時區的時間戳

和太平洋的「P」字段或山的「M」字段「時區」。

我需要創建類型的字段「時間戳和時區」

鑑於這兩個領域我有,是有辦法做到這一點,正確地考慮了夏令時?

具體地說: 時間戳:2013年11月3日01:00:00 時區: 「P」 將成爲:2013年11月3日01:00:00-07

和 時間戳:2013 -11-03 03:00:00 時區: 「P」 將成爲:2013年11月3日03:00:00-08

+0

您的問題在編輯後更有意義,但根本問題依然存在。 「2013-11-03 01:00:00」仍然不明確:可能是「2013-11-03 00:59:00-07」或分鐘後的分鐘「2013-11-03 01:59:00」 00-07" 。 – Bruno

回答

0

檢查這使得任何意義,你

set timezone to 'PST8PDT'; 

select now(); 
       now    
------------------------------- 
2013-09-28 03:24:20.169189-07 

select ts, 
    ts at time zone 'PST' as "PST", 
    ts at time zone 'PDT' as "PDT" 
from (values 
    ('2013-11-03 01:00:00'::timestamp), 
    ('2013-11-03 02:00:00'), 
    ('2013-11-03 03:00:00') 
) s (ts) 
; 
     ts   |   PST   |   PDT   
---------------------+------------------------+------------------------ 
2013-11-03 01:00:00 | 2013-11-03 01:00:00-08 | 2013-11-03 01:00:00-07 
2013-11-03 02:00:00 | 2013-11-03 02:00:00-08 | 2013-11-03 01:00:00-08 
2013-11-03 03:00:00 | 2013-11-03 03:00:00-08 | 2013-11-03 02:00:00-08 
1

首先,當說結果將變成例如2013-11-03 01:00:00-07,應該補充說這實際上取決於SQL客戶端的時區設置。例如,歐洲時間的會話永遠不會讀取2013-11-03 01:00:00-07作爲timestamp with time zone的值,因爲沒有歐洲國家在GMT-07

也就是說,轉換可以使用AT TIME ZONE構造應用於timestamp without time zone

假設我們從US/Pacific時區運行此:

SET time zone 'US/Pacific'; 

SELECT t AT TIME ZONE 
    case z when 'P' then 'US/Pacific' when 'M' then 'US/Mountain' end 
    from (values 
    ('2013-11-03 01:00:00'::timestamp, 'P'), 
    ('2013-11-03 03:00:00'::timestamp, 'P') 
) as v(t,z); 

結果是:

 
     timezone   
------------------------ 
2013-11-03 01:00:00-08 
2013-11-03 03:00:00-08 

2013-11-03 01:00:00 AT time zone 'US/Pacific'具有不確定性,因爲它屬於小時跨度最先發生在-07時區,然後在DST切換後第二次在-08時區。 postgres的解釋是在-08時區看到它。如果我們考慮之前的分鐘,它將落入時區-07

1

TIMESTAMP WITHOUT TIME ZONETIMESTAMP WITH TIME ZONETIMESTAMPTZ)之間的差異可能是非常棘手的問題,如果你考慮他們的名字。 (實際上,規範似乎有足夠的混淆,因此各種RDBMS以不同的方式實現它。)

在PostgreSQL中,兩種類型都不存儲存儲時值的時區,但TIMESTAMPTZ將值存儲爲基於UTC參考的精確時刻,而TIMESTAMP WITHOUT TIME ZONE總是相對的。

  • 當被查詢時,一個TIMESTAMPTZ將被調整爲表示在作爲初始存儲的同一時刻(在取其世界這是一部分)作爲瞬間這將是在當前時區配置用於通過所述客戶端。
  • A TIMESTAMP WITHOUT TIME ZONE將始終與客戶端配置的時區相同,即使您查詢的時區不同:由2013-11-03 03:00:00表示的時刻將不明確,並取決於客戶端設置。

想必,你與你的TIMESTAMP WITHOUT TIME ZONE使用你的「時區」列(PM),以補償輸入價值的不確定性。

原則上,如果您的時區與存儲時間戳的時區相同,則應該返回相同的值,因此如果您已將客戶端設置爲US/Pacific時區,已在P時區儲存2013-11-03 03:00:00,您應該返回2013-11-03 03:00:00。但是,這隻有在相對值沒有歧義時纔有效。

在你的第一個例子這裏的問題是,已經有一些模糊:

時間戳:2013年11月3日01:00:00時區:「P」將成爲:2013年11月3日 01:00:00-07

2013-11-03 01:00:00可以表示時間兩個不同時刻在US/Pacific時區,所以只有2013-11-03 01:00:00"P",你已經失去了信息,你將無法恢復。

如果您只是想根據當時的DST設置在'-08'和'-07'之間進行切換,這將自動完成,但您應該使用TIMESTAMPTZ第一個地方,準確地說,你在哪個時間表現。

這裏就是初始時間區保持一個例子,所以你可以看到之間的 '-08' 和改變 '-07':

SET time zone 'US/Pacific'; 

SELECT t AS "Date/Time for US/Pacific", 
     t AT time zone 'UTC' "Date/Time in UTC" 
FROM (VALUES 
    ('2013-11-03 00:00:00-07'::timestamptz), 
    ('2013-11-03 01:00:00-07'::timestamptz), 
    ('2013-11-03 02:00:00-07'::timestamptz), 
    ('2013-11-03 03:00:00-07'::timestamptz)) AS v(t); 

結果:

| DATE/TIME FOR US/PACIFIC | DATE/TIME IN UTC | 
|--------------------------|---------------------| 
| 2013-11-03 00:00:00-07 | 2013-11-03 07:00:00 | 
| 2013-11-03 01:00:00-07 | 2013-11-03 08:00:00 | 
| 2013-11-03 01:00:00-08 | 2013-11-03 09:00:00 | 
| 2013-11-03 02:00:00-08 | 2013-11-03 10:00:00 | 

不幸,只有兩個字段無法處理DST更改。

當然值得您閱讀Date/Time types section of the PostgreSQL manual,並注意AT TIME ZONE documentation表中的「返回類型」列,以便更好地理解這些問題。

相關問題