我花了很多时间阅读最佳做法'当谈到处理Postgres中的时间戳时,并且有很多相互矛盾的答案。使用TIMESTAMPTZ
数据类型时,我假设NOW()
和NOW() at time zone 'utc'
会导致在数据库中插入相同的数据。网上的大量评论表明,时区内部并未实际存储,而是转换为UTC。
为什么会这样,当我运行以下内容时,我不会得到重复的结果?
CREATE TABLE testtime(
mytime TIMESTAMPTZ,
descr VARCHAR
);
INSERT INTO testtime VALUES
(NOW(), 'Now at NZST'),
(NOW() AT TIME ZONE 'utc', 'Now at UTC');
SELECT *
FROM testtime;
结果:
2016-02-17 02:08:30.845071 Now at NZST
2016-02-16 13:08:30.845071 Now at UTC
答案 0 :(得分:3)
原因是从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早一个小时(冬季):
SET timezone = 'Europe/Vienna';
SELECT now() AS now1
, now() AT TIME ZONE 'UTC' AS now2
, (now() AT TIME ZONE 'UTC')::timestamptz AS now3;
now1 | now2 | now3 -------------------------------+----------------------------+------------------------------- 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;
now1 | now2 | now3 -------------------------------+----------------------------+------------------------------- 2016-02-16 13:30:58.739772+00 | 2016-02-16 13:30:58.739772 | 2016-02-16 13:30:58.739772+00
注意前两列如何具有相同的值 - 即使now1
中的文本表示看起来不同,因为它被调整到会话的时区,值是相同。
第三列有一个不同的值,因为假定了类型转换的不同时区。
基础知识: