2015-01-06 142 views
1

我有一張表,其數據類型爲timestamp without time zone,我試圖將其轉換爲時區,並在給定時區沒有時區。將時間戳轉換爲Postgres中特定時區的時間戳

這些都是我的Postgres 9.3設置

select current_setting('TIMEZONE'); 
current_setting 
----------------- 
Hongkong 

select * from pg_timezone_names where name = 'Hongkong'; 
    name | abbrev | utc_offset | is_dst 
----------+--------+------------+-------- 
Hongkong | HKT | 08:00:00 | f 

這裏是我做的將其轉換爲HKT:

-- this SQL gives me what I expected 
select '2015-01-05 12:00:00'::timestamp without time zone 
at time zone 'UTC' 
at time zone 'HKT'; 
--------------------- 
2015-01-05 20:00:00 

-- Shouldn't this produce the same result with the above one? 
-- How do I make this work? 
-- Don't tell me to change it to UTC-08:00 ... 
select '2015-01-05 12:00:00'::timestamp without time zone 
at time zone 'UTC' 
at time zone 'UTC+08:00'; 
--------------------- 
2015-01-05 04:00:00 -- WHY? 
+0

使用'在時間ZONE'運營商。 –

回答

1

這背後的原因是爲什麼你真的不應該使用時區PostgreSQL中的偏移量(除非你確切地知道你在做什麼)。

時區'UTC+08:00'是POSIX風格的時區規範,'Hongkong'是準確的時區名稱,'HKT'是其中一個縮寫。

pg_timezone_names系統視圖的utc_offset列是defined從UTC偏移(正裝置格林威治

但在POSIX風格的時區規範,偏移部分是different

...要牢記的另一個問題是,在POSIX時區名稱,正面偏置用於位置格林威治西。在其他地方,PostgreSQL遵循ISO-8601慣例,即格林威治的正時區偏移量爲東部

所以,而是採用偏移量(以間隔),或POSIX風格的時區規範,你應該使用:

  • 時區的縮寫,如果你要處理的夏時制規則的擁有,
  • 確切的時區名稱,其他地方(首選)。

總之,這是縮寫和全名之間的區別:縮寫代表一個特定的UTC的偏移量,而許多的全名意味着本地夏令時間規則,所以有兩種可能UTC偏移。

使事情複雜化,一些司法轄區使用相同的時區縮寫來表示在不同時間的UTC偏移量;例如,在莫斯科,MSK在某些年代意味着UTC + 3,在其他時期意味着UTC + 4。 PostgreSQL根據它們在指定日期(或最近的含義)的意思解釋這些縮寫;但是,與上面的EST例子一樣,這不一定與那天的當地民事時間相同。

但最簡單的解決方案是使用timestamp with time zone:您已經設定了TimeZone設置'Hongkong',所以timestamp with time zone值將顯示在該時間段你(PostgreSQL的)客戶端。

set time zone 'Hongkong'; 

select current_setting('TimeZone') TimeZone, 
     dt original, 
     dt AT TIME ZONE 'UTC' AT TIME ZONE 'UTC+08:00' "UTC+08:00", 
     dt AT TIME ZONE 'UTC' AT TIME ZONE 'UTC+8' "UTC+8", 
     dt AT TIME ZONE 'UTC' AT TIME ZONE 'UTC-8' "UTC-8", 
     dt AT TIME ZONE 'UTC' AT TIME ZONE INTERVAL '+08:00' "INTERVAL +08:00", 
     dt AT TIME ZONE 'UTC' AT TIME ZONE 'HKT' "HKT", 
     dt AT TIME ZONE 'UTC' AT TIME ZONE 'Hongkong' "Hongkong", 
     dt AT TIME ZONE 'UTC' "with time zone" 
from (values (timestamp '2015-01-05 12:00:00')) v(dt); 

-- TIMEZONE | ORIGINAL   | UTC+08:00 
-- ---------+---------------------+-------------------- 
-- Hongkong | 2015-01-05 12:00:00 | 2015-01-05 04:00:00 

-- UTC+8    | UTC-8    | INTERVAL +08:00 
-- --------------------+---------------------+-------------------- 
-- 2015-01-05 04:00:00 | 2015-01-05 20:00:00 | 2015-01-05 20:00:00 

-- HKT     | HONGKONG   | WITH TIME ZONE 
-- --------------------+---------------------+----------------------- 
-- 2015-01-05 20:00:00 | 2015-01-05 20:00:00 | 2015-01-05 20:00:00+08 

SQLFiddle

相關問題