Postgresql

帶有 AT TIME ZONE 和 UTC 偏移量的怪事

  • March 21, 2022

我不明白這兩列之間的區別。美國/芝加哥時區是 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 樣式的時區規範,形式為*STDoffsetor STDoffsetDST,其中STD*是區域縮寫,offset 是 *offsetUTC 以西的小時數,並且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 的一部分。明確不鼓勵使用它。看:

引用自:https://dba.stackexchange.com/questions/160065