【问题标题】:postgresql `at time zone` incorrect behaviour?postgresql`在时区`不正确的行为?
【发布时间】:2019-06-06 12:22:54
【问题描述】:

我有一个简单的 postgresql 表,其中包含以下数据:

create table ti (
  l text,
  t timestamp without time zone
  );

insert into ti(l, t) values ('now', now());

我使用at time zone 进行选择,我希望UTC + 5.30 hours

select now(), t, t at time zone 'Asia/Kolkata' from ti;

但这就是我得到的:

now|    t|  timezone
2019-06-06T12:11:42.576388Z|    2019-06-06T11:50:48.178689Z|    2019-06-06T06:20:48.178689Z

它减去了 5.30 小时而不是添加它们。

Sqlfiddle here

【问题讨论】:

    标签: postgresql timezone


    【解决方案1】:

    now() 返回带有时区的时间戳。当将时区信息转换为没有时区的时间戳时,时区信息将被剥离,当它保存在您的表中时,但保存在那里的实际值将取决于会话时区。

    您可以很容易地看到这种行为:

    postgres=# begin;
    BEGIN
    postgres=# set time zone utc;
    SET
    postgres=# insert into test select now();
    INSERT 0 1
    postgres=# set time zone 'US/Eastern';
    SET
    postgres=# insert into test select now();
    INSERT 0 1
    postgres=# select * from test;
                 a
    ----------------------------
     2019-06-06 12:46:10.475424
     2019-06-06 08:46:10.475424
    (2 rows)
    
    

    在您发表评论后进行更多解释。我认为您遇到的问题是在时间戳和时间戳之间进行转换。如果您只使用 timestamptz,那么时间戳就不会那么混乱了。让我们从讨论中删除 now(),因为这增加了额外的复杂性,因为从 now() 的结果转换为没有时区的时间戳取决于会话时区。

    select '2019-06-06 12:00:00UTC'::timestamp with time zone, 
           ('2019-06-06 12:00:00UTC'::timestamp with time zone) at time zone 'Asia/Kolkata';
          timestamptz       |      timezone
    ------------------------+---------------------
     2019-06-06 12:00:00+00 | 2019-06-06 17:30:00
    

    我相信这是你所期望的?我们在特定时区将带时区的时间戳转换为不带时区的时间戳。

    不过,您所做的与此类似:

    select '2019-06-06 12:00:00UTC'::timestamp with time zone, 
      (('2019-06-06 12:00:00UTC'::timestamp with time zone)::timestamp without time zone) at time zone 'Asia/Kolkata';
          timestamptz       |        timezone
    ------------------------+------------------------
     2019-06-06 12:00:00+00 | 2019-06-06 06:30:00+00
    (1 row)
    

    如果您可以存储带时区的时间戳而不是不带时区的时间戳,我认为您会发现这一点不会那么混乱。

    【讨论】:

    • 谢谢,我试过insert into ti(l, t) values ('now', '2019-06-06 12:00:00');,结果是一样的。还有2019-06-06 12:00:00 at time zone 'UTC'
    • 但是您是否首先将列定义更改为“timestamp with time zone”而不是“timestamp without time zone”?
    • 当pg内部将timestamp存储为UTC时,为什么我必须转换两次?
    • 它不会在 UTC 内部存储时间戳。它在内部将 timestamptz 存储为 UTC。
    猜你喜欢
    • 2013-11-17
    • 1970-01-01
    • 2014-06-17
    • 2022-01-05
    • 2016-12-15
    • 2018-06-07
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    相关资源
    最近更新 更多