【问题标题】:Postgres timestamp conversion is backwardsPostgres 时间戳转换是向后的
【发布时间】:2021-01-13 19:29:18
【问题描述】:

服务器位于 EST,我将 timestamptz 存储为 lastlogin

似乎从 UTC 到 EST 的转换正在倒退。

select lastlogin at time zone 'EST' as lastlogin from users where id = 1;
-- > 2021-01-13 18:56:28

select lastlogin at time zone 'UTC' as lastlogin from users where id = 1;
-- > 2021-01-13 13:56:28

如果从 UTC 转换为 EST 我减去 5 小时,为什么未来 EST 是 5 小时?就好像转换为 UTC 实际上给了我 EST 时间,而转换为 EST 给了我 UTC 时间。

但这有效:

select NOW() at time zone 'EST', NOW() at time zone 'UTC';
-- > 2021-01-13 14:23:21 2021-01-13 19:23:21

编辑:

我发现进行两次转换似乎可行:

select lastlogin at time zone 'UTC' at time zone 'EST' as lastlogin from users where id = 1;
-- > 2021-01-13 13:56:28

这显示在Popsql How to Convert UTC to Local Time Zone in PostgreSQL。是不是第一个at time zone会设置时间的时区,而第二个会实际进行转换?

【问题讨论】:

  • select lastlogin from users where id = 1; 的值是多少?
  • 2021-01-13 18:56:28
  • 很高兴您找到了答案,但请注意。不要使用 EST 作为时区;它是时区缩写。而是使用完整的时区名称;美国/东部或美国/纽约,或其他偏移 -05:00 - 其中有 34***)。这是因为全名会根据夏令时自动调整,而缩写不会。 *** select * from pg_timezone_names where abbrev = 'EST';

标签: postgresql timezone


【解决方案1】:

我想通了。

首先,显然时间戳可能不是timestamptz。 DBeaver 说这是当我查看表格列时,但如果我查询它会报告timestamp。 Pgcli 还说它是timestamp

也就是说,我在 postgresql 文档9.9.3 AT TIME ZONE 中发现:

AT TIME ZONE 运算符将不带时区的时间戳转换为/从带时区的时间戳,以及将带时区值的时间转换为不同的时区。。 p>

我的问题编辑中的解释是正确的。 AT TIME ZONE 上的 timestamp 会将时间的时区设置为您指定的任何时间,然后第二个 AT TIME ZONE 将转换它。

【讨论】:

  • psql 中,\d user 显示最后一次登录的内容。我猜是timestamptz
  • 嗯,我注意到我们的两个数据库的 lastlogin 是不同的,一个是 timestamptz,另一个是 timestamp。这就是我感到困惑的地方。这个例子中的那些是timestamp
  • 查看我的答案以获得进一步的解释。如果没有其他问题,您会发现为什么 timestamptztimestamp 更好。
【解决方案2】:

您所看到的以及为什么将时间戳值存储在 timestamptz 中很重要:

set timezone = 'US/Eastern';

test(5432)=> \d ts_test 
                         Table "public.ts_test"
  Column  |            Type             | Collation | Nullable | Default 
----------+-----------------------------+-----------+----------+---------
 ts_tz    | timestamp with time zone    |           |          | 
 ts       | timestamp without time zone |           |          | 
 ts_txt   | character varying           |           |          | 
 time_fld | time without time zone      |           |          | 

-- A timestamptz field always stores the value as UTC. A timestamp field is stored -- as a naive value. In below the timestamptz value is rotated to EST as that what -- the timezone is set to. The timestamp is also displayed in EST but with no time -- zone value, so naive.

select ts_tz, ts from ts_test ;
             ts_tz              |             ts             
--------------------------------+----------------------------
 01/14/2021 11:37:13.217229 EST | 01/14/2021 11:37:13.217229

-- Here the time zone is being explicitly set and both values are the same as 
-- timezone = 'EST'. The formally naive value does pick up a time zone designation -- per the docs "timestamp without time zone AT TIME ZONE zone Return Type --timestamp with time -- zone"

select ts_tz AT TIME ZONE 'EST', ts AT TIME ZONE 'EST' from ts_test;
          timezone          |            timezone            
----------------------------+--------------------------------
 01/14/2021 11:37:13.217229 | 01/14/2021 11:37:13.217229 EST

-- Here the the timestamptz value correctly gets rotated to UTC. The timestamp 
-- value gets set to UTC then gets rotated back to EST

 select ts_tz AT TIME ZONE 'UTC', ts AT TIME ZONE 'UTC' from ts_test;
          timezone          |            timezone            
----------------------------+--------------------------------
 01/14/2021 16:37:13.217229 | 01/14/2021 06:37:13.217229 EST


【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-26
    • 2021-08-18
    • 2013-06-15
    • 2015-03-03
    • 2016-06-20
    • 1970-01-01
    • 1970-01-01
    • 2020-07-26
    相关资源
    最近更新 更多