原因是从timestamp 到timestamptz 的隐式类型转换。
-
now() 返回数据类型timestamptz。
-
now() AT TIME ZONE 'UTC' 返回数据类型timestamp。
-
(now() AT TIME ZONE 'UTC')::timestamptz 将 timestamp 转换为 timestamptz,在此过程中假设您当前的时区。这就是引入差异的地方。
当您将INSERT 一个timestamp 值放入timestamptz 列时,就会发生这种情况。 Postgres 必须假设 一些 时区。您似乎已经预料到会假定 UTC。不过,更合理的默认设置是当前时区设置。如果您在会话中设置 UTC,您将获得预期的行为。
演示:
我的时区是“欧洲/维也纳”,目前比 UTC 早 1 小时(冬季期间):
SET timezone = 'Europe/Vienna';
SELECT now() AS now1
, now() AT TIME ZONE 'UTC' AS now2
, (now() AT TIME ZONE 'UTC')::timestamptz AS now3;
现在1 |现在2 |现在3
-------------------------------------------+------------------ ----------+-------------------
2016-02-16 14:30:07.243082+01 | 2016-02-16 13:30:07.243082 | 2016-02-16 13:30:07.243082+01
与 'UTC' 相同作为会话的时区设置:
SET timezone = 'UTC';
SELECT now() AS now1
, now() AT TIME ZONE 'UTC' AS now2
, (now() AT TIME ZONE 'UTC')::timestamptz AS now3;
现在1 |现在2 |现在3
-------------------------------------------+------------------ ----------+-------------------
2016-02-16 13:30:58.739772+00 | 2016-02-16 13:30:58.739772 | 2016-02-16 13:30:58.739772+00
注意前两列如何具有相同的值 - 即使now1 中的文本表示看起来不同,因为它已根据会话的时区进行了调整,但值是相同的。
第三列有一个不同的值,因为为类型转换假定了不同的时区。
这里的基本信息: