PostgreSQL 时间戳和时区:为什么我读到的结果与我写的不同?
PostgreSQL Timestamps and Time zones: Why am I reading different results than I wrote?
我试图了解时间戳是怎么回事,以及 postgreSql 如何处理时区,但一直很不成功。
这是我为学习而创建的示例脚本:
drop table if exists timestampTest;
create table timestampTest(
ts timestamp with time zone
);
insert into timestampTest (ts) values (to_timestamp(0) at time zone 'utc');
select
to_timestamp(0) at time zone 'utc' INSERTED,
ts at time zone 'utc' RETRIEVED_UTC,
ts RETRIEVED_DEFAULT,
extract(epoch from ts) RETRIEVED_TS_DEFAULT,
extract(epoch from ts at time zone 'utc') RETRIEVED_TS_UTC,
extract(epoch from to_timestamp(0) at time zone 'utc') INSERTED_TS
from timestampTest
当我在笔记本电脑 (PostgreSQL 9.3.5 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2, 64-bit
) 上以德国时间运行脚本时,它输出:
inserted | retrieved_utc | retrieved_default | retrieved_ts_default | retrieved_ts_utc | inserted_ts
---------------------+---------------------+------------------------+----------------------+------------------+-------------
1970-01-01 00:00:00 | 1969-12-31 23:00:00 | 1970-01-01 00:00:00+01 | -3600 | -3600 | 0
这让我感到震惊,因为我预计 inserted
和 retrieved_utc
是相同的,因为我能看到的唯一区别是一旦值存储在 table 和然后加载不应更改值(应该吗?)。
此外,我希望所有时间戳值都相同(自 unix 纪元 UTC 开始以来的秒数)。我最不希望与其他值不同的值是 inserted_ts
。然而,它确实不同。为什么?
然后,我在我正在运行的服务器 (PostgreSQL 9.3.5 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2, 64-bit
) 上执行了该脚本,该服务器也位于德国,其时间设置为德国时间,这与其说是有意为之,不如说是偶然。它给出以下结果:
inserted | retrieved_utc | retrieved_default | retrieved_ts_default | retrieved_ts_utc | inserted_ts
---------------------+---------------------+------------------------+----------------------+------------------+-------------
1970-01-01 00:00:00 | 1969-12-31 23:00:00 | 1970-01-01 00:00:00+01 | -3600 | -7200 | -3600
这里到底发生了什么?
更新:我刚刚尝试在笔记本电脑上将系统时间设置为 UTC。在这种情况下,我得到了想要的结果:
inserted | retrieved_utc | retrieved_default | retrieved_ts_default | retrieved_ts_utc | inserted_ts
---------------------+---------------------+------------------------+----------------------+------------------+-------------
1970-01-01 00:00:00 | 1970-01-01 00:00:00 | 1970-01-01 01:00:00+01 | 0 | 0 | 0
是的,这是我实际期望的结果,并不感到惊讶(好吧,令我惊讶的是 retrieved_default
仍然以德国时间显示,但至少它仍然指的是同一点及时)。但是将我的计算机的时区永久设置为 UTC 不是一种选择。无论服务器上恰好将哪个时区设置为系统时区,我都需要弄清楚如何处理这些事情。
当您在时区 'UTC' 使用 to_timestamp(0) 插入时,"at time zone" 部分会从 return 类型中删除时区,从而以"local",即在插入时重新转换回 UTC。您的插入语句中不需要 "at time zone 'utc'"。
为了更好地了解发生了什么,请尝试以下操作:
set timezone='America/Chicago';
select to_timestamp(0), (to_timestamp(0) at time zone 'UTC') at time zone 'UTC'
我试图了解时间戳是怎么回事,以及 postgreSql 如何处理时区,但一直很不成功。
这是我为学习而创建的示例脚本:
drop table if exists timestampTest;
create table timestampTest(
ts timestamp with time zone
);
insert into timestampTest (ts) values (to_timestamp(0) at time zone 'utc');
select
to_timestamp(0) at time zone 'utc' INSERTED,
ts at time zone 'utc' RETRIEVED_UTC,
ts RETRIEVED_DEFAULT,
extract(epoch from ts) RETRIEVED_TS_DEFAULT,
extract(epoch from ts at time zone 'utc') RETRIEVED_TS_UTC,
extract(epoch from to_timestamp(0) at time zone 'utc') INSERTED_TS
from timestampTest
当我在笔记本电脑 (PostgreSQL 9.3.5 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2, 64-bit
) 上以德国时间运行脚本时,它输出:
inserted | retrieved_utc | retrieved_default | retrieved_ts_default | retrieved_ts_utc | inserted_ts
---------------------+---------------------+------------------------+----------------------+------------------+-------------
1970-01-01 00:00:00 | 1969-12-31 23:00:00 | 1970-01-01 00:00:00+01 | -3600 | -3600 | 0
这让我感到震惊,因为我预计 inserted
和 retrieved_utc
是相同的,因为我能看到的唯一区别是一旦值存储在 table 和然后加载不应更改值(应该吗?)。
此外,我希望所有时间戳值都相同(自 unix 纪元 UTC 开始以来的秒数)。我最不希望与其他值不同的值是 inserted_ts
。然而,它确实不同。为什么?
然后,我在我正在运行的服务器 (PostgreSQL 9.3.5 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2, 64-bit
) 上执行了该脚本,该服务器也位于德国,其时间设置为德国时间,这与其说是有意为之,不如说是偶然。它给出以下结果:
inserted | retrieved_utc | retrieved_default | retrieved_ts_default | retrieved_ts_utc | inserted_ts
---------------------+---------------------+------------------------+----------------------+------------------+-------------
1970-01-01 00:00:00 | 1969-12-31 23:00:00 | 1970-01-01 00:00:00+01 | -3600 | -7200 | -3600
这里到底发生了什么?
更新:我刚刚尝试在笔记本电脑上将系统时间设置为 UTC。在这种情况下,我得到了想要的结果:
inserted | retrieved_utc | retrieved_default | retrieved_ts_default | retrieved_ts_utc | inserted_ts
---------------------+---------------------+------------------------+----------------------+------------------+-------------
1970-01-01 00:00:00 | 1970-01-01 00:00:00 | 1970-01-01 01:00:00+01 | 0 | 0 | 0
是的,这是我实际期望的结果,并不感到惊讶(好吧,令我惊讶的是 retrieved_default
仍然以德国时间显示,但至少它仍然指的是同一点及时)。但是将我的计算机的时区永久设置为 UTC 不是一种选择。无论服务器上恰好将哪个时区设置为系统时区,我都需要弄清楚如何处理这些事情。
当您在时区 'UTC' 使用 to_timestamp(0) 插入时,"at time zone" 部分会从 return 类型中删除时区,从而以"local",即在插入时重新转换回 UTC。您的插入语句中不需要 "at time zone 'utc'"。
为了更好地了解发生了什么,请尝试以下操作:
set timezone='America/Chicago';
select to_timestamp(0), (to_timestamp(0) at time zone 'UTC') at time zone 'UTC'