【问题标题】:PostgreSQL Timestamps and Time zones: Why am I reading different results than I wrote?PostgreSQL 时间戳和时区:为什么我读到的结果与我写的不同?
【发布时间】:2015-03-03 13:09:00
【问题描述】:

我正在尝试了解时间戳的内容以及 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

这让我感到震惊,因为我希望 insertedretrieved_utc 是相同的,因为我能看到的唯一区别是,一旦将值存储在表中然后加载它不应该改变值(应该吗?)。

此外,我希望所有时间戳值都相同(自 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 不是一种选择。无论服务器上碰巧将哪个时区设置为系统时区,我都需要弄清楚如何处理这些事情。

【问题讨论】:

  • 您使用的是哪个客户端?归根结底,一切都是平等的......而且在这里看小提琴:sqlfiddle.com/#!1/30ecd/1
  • @JorgeCampos:我从 postgre 附带的命令行 psql 客户端复制并粘贴了两个示例。在我的笔记本电脑上,我还使用了 GUI pgAdmin,它给出了相同的结果。太糟糕了,在 sqlfiddle 上没有时间戳设置。也许他们的系统时间设置为UTC,也许在这种情况下结果不同? (只是尝试将我的笔记本电脑时区设置为 UTC,在这种情况下,我得到与 sqlfiddle 相同的结果)
  • 我发现这个问题stackoverflow.com/questions/9202857/… 与您的问题有关(不完全),可能与 GMT 和 CMT 有关。看看

标签: sql postgresql


【解决方案1】:

当您在时区“UTC”使用 to_timestamp(0) 插入时,“at time zone”部分会从返回类型中删除时区,从而以“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'

【讨论】:

  • 我倾向于长篇大论地思考“好像我没有尝试那个 $%!”。但显然我没有。你完全正确,谢谢一百万!
猜你喜欢
  • 1970-01-01
  • 2019-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-16
  • 2012-11-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多