帶有 AT TIME ZONE 和 UTC 偏移量的怪事
我不明白這兩列之間的區別。美國/芝加哥時區是 UTC-6,所以我希望兩者都返回相同的結果:
select timezone('America/Chicago', '2017-01-01 12:00:00'::TIMESTAMP AT TIME ZONE 'UTC'), timezone('UTC-6' , '2017-01-01 12:00:00'::TIMESTAMP AT TIME ZONE 'UTC');
然而,結果是:
2017-01-01 06:00:00 | 2017-01-01 18:00:00
此外,這種行為非常尷尬,
SELECT '1:00 -1'::time with time zone AT TIME ZONE '-1'; timezone ------------- 03:00:00+01
誰能解釋一下?
時區名稱比縮寫或簡單的時區偏移量包含更多資訊。*‘UTC-6’*是一種“POSIX 風格的時區規範”,它只是一個縮寫加上偏移量。時區
PostgreSQL 允許您以三種不同的形式指定時區:
- 完整的時區名稱,例如
America/New_York
.$$ … $$
- 時區縮寫,例如
PST
。$$ … $$
- 除了時區名稱和縮寫之外,PostgreSQL 將接受 POSIX 樣式的時區規範,形式為*
STDoffset
orSTDoffsetDST
,其中STD
*是區域縮寫,offset 是 *offset
UTC 以西的小時數,並且DST
*是可選的夏令時區縮寫,假設在給定的偏移量之前站立一小時。您觀察到的差異源於另一個奇怪之處。您必須使用**
+
而不是-
**:timezone('**UTC+6**', '2017-01-01 12:00:00'::TIMESTAMP AT TIME ZONE 'UTC')
要記住的另一個問題是,在 POSIX 時區名稱中,正偏移量用於格林威治以西的位置。在其他任何地方,PostgreSQL 都遵循 ISO-8601 約定,即正時區偏移量位於格林威治以東。
然而,即使修正了偏移誤差,兩個表達式仍然不等價。除此之外,像*“美國/芝加哥”*這樣的時區名稱還考慮了夏令時 (DST) 的規則。
順便說一句,您的表達式可以簡化為:
timestamptz '2017-01-01 12:00:00 +0' AT TIME ZONE 'UTC+6'
但是您可能希望 time zone name是安全的:
timestamptz '2017-01-01 12:00:00 +0' AT TIME ZONE 'America/Chicago'
有關的:
要解決您的第二個範例:
SELECT '1:00 -1'::time with time zone AT TIME ZONE '-1';
簡化的等效語法:
SELECT timetz '1:00 -1' AT TIME ZONE '-1';
字面的兩個實例
-1
具有不同的含義。第一個偏移量是*timetz*
表示格林威治以東位置的文字的一部分(符合 SQL 標準)。第二個是POSIX 風格的時區規範,表示格林威治以西的偏移量。在沒有區域規範的情況下,假設 UTC 為基準。看:另請注意,
AT TIME ZONE
構造返回timetz
輸入timetz
。它只是將時間文字重新建立在不同的偏移量上。這與它與timestamp
/timestamptz
輸入的使用不同,其中數據類型也被切換。但根本不要使用數據類型
timetz
(time with time zone
) 。它被設計破壞並且只包含在 Postgres 中,因為它是標準 SQL 的一部分。明確不鼓勵使用它。看: