【问题标题】:Store/Retrieve a timestamp with or without timezone存储/检索带有或不带有时区的时间戳
【发布时间】:2016-10-03 07:24:07
【问题描述】:

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

我有以下设置:

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 
    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

问题 1

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

问题 2

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

例如:

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

【问题讨论】:

    标签: postgresql datetime timestamp-with-timezone


    【解决方案1】:

    问题 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)
    

    【讨论】:

    • 第一个问题的答案是记住差异的简单方法,谢谢!也不知道您可以使用 SET 关键字设置时区。伟大的!但是当您的客户在不同的时区时,您会怎么做,那么您是否总是对每个查询都执行 SET TIMEZONE = xxxxx 呢?
    • 如果一个会话必须为不同时区的客户提供服务,例如在连接池中,则每次切换客户时都必须设置时区。但是,如果您在应用程序代码中处理时区,您必须在应用程序中做同样的事情,对吧?
    • 就我而言,我有一个客户端也可以连接的 REST API。因此,如果我将时间戳存储为“带区域的时间戳”并获取数据,我只需将客户端应用程序设置为正确的时区即可显示正确的时间,对吗?我的后端不需要知道最终用户在哪个时区?
    • 只要将timestamp with time zone 转换为字符串,该设置就相关。您的夏威夷客户是否乐于以2016-10-03 07:03:16.63818+00 获得她的结果?
    • 好的,我明白你的意思是,当它被转换为字符串以在列表、打印输出或其他方式中显示它时,该设置是相关的。但是我也有这个日历,它有一个时区设置,所以我可以在不执行 SET Timezone = xxxx 的情况下获取时间戳,并在客户端应用程序的日历上设置时区。我想我的想法是对的?
    猜你喜欢
    • 2014-01-07
    • 1970-01-01
    • 2019-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-11
    • 2010-11-20
    相关资源
    最近更新 更多