Store/Retrieve 带或不带时区的时间戳

Store/Retrieve a timestamp with or without timezone

我想测试时间戳和时间戳与时区字段的一些差异。但是我遇到了一些我无法真正理解为什么它会这样工作的东西。

我有以下设置:

CREATE TABLE tbl_test_timezones (
    first_date timestamp with time zone,
    second_date timestamp 
)

我插入了一些测试数据:

insert into tbl_test_timezones (first_date, second_date) values (now(), now());

现在我想在执行 select

时检查两个字段之间的差异
select 
    first_date, 
    first_date at time zone 'Europe/Brussels' as first_date_wt, 
    second_date, 
    second_date at time zone 'Europe/Brussels' as second_date_wt
from tbl_test_timezones

which gives me the following result

first_date:     2016-10-03 07:03:16.63818+00    
first_date_wt:  2016-10-03 09:03:16.63818   
second_date:    2016-10-03 07:03:16.63818   
second_date_wt: 2016-10-03 05:03:16.63818+00

问题一

我想知道为什么 second_date_wt 是 -2 而不是像 first_date_wt 那样的 +2?

问题二

假设我的应用程序将时间戳与时区一起存储,并且用户想要获取一些具有该时间戳的记录。您是否必须为用户存储某种用户设置,他可以在其中输入他的时区,并在检索时始终将其包含在 select 查询中?或者您更喜欢只获取它并在客户端应用程序中执行时区操作?

例如:

select start_date at time zone (
    select user_time_zone from tbl_user_settings where user_id = 2
)
from tbl_projects

或者只是

select start_date 
from tbl_projects

问题 1 的答案

这两个值有不同的含义。

first_date AT TIME ZONE 'Europe/Brussels'

答案:此时布鲁塞尔的挂钟显示什么?

second_date AT TIME ZONE 'Europe/Brussels'

回答:布鲁塞尔的挂钟在什么时间点显示这个值?

问题 2 的答案

最好的方法是将配置参数 TimeZone 设置为客户端应用程序的时区。然后所有 timestamp with time zone 值将显示在该时区中,并且 timestamp without time zone 值将被解释为该时区中的值:

SHOW TimeZone;

   TimeZone
---------------
 Europe/Vienna
(1 row)

SELECT
   TIMESTAMP WITH TIME ZONE '2016-10-01 00:00:00 UTC' AS "midnight at UTC",
   CAST(
      TIMESTAMP WITHOUT TIME ZONE '2016-10-01 00:00:00'
      AS TIMESTAMP WITH TIME ZONE
   ) AS "midnight local";

    midnight at UTC     |     midnight local
------------------------+------------------------
 2016-10-01 02:00:00+02 | 2016-10-01 00:00:00+02
(1 row)

SET TimeZone = 'America/Los_Angeles';

SELECT
   TIMESTAMP WITH TIME ZONE '2016-10-01 00:00:00 UTC' AS "midnight at UTC",
   CAST(
      TIMESTAMP WITHOUT TIME ZONE '2016-10-01 00:00:00'
      AS TIMESTAMP WITH TIME ZONE
   ) AS "midnight local";

    midnight at UTC     |     midnight local
------------------------+------------------------
 2016-09-30 17:00:00-07 | 2016-10-01 00:00:00-07
(1 row)