在PostgreSQL中表示未来时间

在PostgreSQL中表示未来时间,postgresql,datetime,timezone,timestamp-with-timezone,Postgresql,Datetime,Timezone,Timestamp With Timezone,我已经习惯于将过去的日期作为UTC存储在数据库中,因为事实上这是事件发生的时间。对于将来的日期,我会将其存储在特定的时区中,以避免诸如闰秒或时区规则更改之类的更改 Postgres具有带时区的时间戳,但在封面下,它将其存储为UTC,从而推断指定的时区是UTC的偏移量。如果时区规则要更改,则该列中不会反映这一点 在这种情况下,建议使用什么?特别是如果您想保护自己不受未来时间zune更改的影响,您应该使用带有时区的时间戳 PostgreSQL在内部存储自2000-01-01 00:00:00以来的微

我已经习惯于将过去的日期作为UTC存储在数据库中,因为事实上这是事件发生的时间。对于将来的日期,我会将其存储在特定的时区中,以避免诸如闰秒或时区规则更改之类的更改

Postgres具有带时区的时间戳,但在封面下,它将其存储为UTC,从而推断指定的时区是UTC的偏移量。如果时区规则要更改,则该列中不会反映这一点

在这种情况下,建议使用什么?

特别是如果您想保护自己不受未来时间zune更改的影响,您应该使用带有时区的
时间戳

PostgreSQL在内部存储自2000-01-01 00:00:00以来的微秒数,这是不受时区更改影响的。如果您不断更新PostgreSQL,它将始终正确显示会话时区的绝对值

PostgreSQL中没有闰秒的规定

对于将来的日期,我会将其存储在特定的时区中,以避免诸如闰秒或时区规则更改之类的更改

这似乎落后了。与其他时区相比,UTC的主要优势在于它不太容易发生意外的未来变化:UTC仅在日历年的已知有限点引入闰秒;而且没有频繁的政治授权的抵消变化

将值存储在某些本地管理的时区中会使这些值(与UTC相比)更容易在未来发生任意、不可预测的含义变化

因此,一般建议是:将所有时间值(无论是日期还是日期+时间)作为UTC存储在数据库中,并在内部作为UTC值进行处理;并仅在外部接口上与本地时区进行转换

对于PostgreSQL,这意味着更喜欢带有时区的时间戳

把它想象成一个日历事件。UTC对此毫无意义

听起来您想要存储一个关于某个时区的localtime。 在这种情况下,将
时间戳
(无时区)和
时区
存储在单独的列中

例如,假设您想要记录2030年2月26日上午10点在芝加哥发生的事件 而且它必须在当地时间上午10点,而不考虑该日期生效的时区规则

如果数据库存储的时间戳没有时区:

unutbu=# select '2030-02-26 10:00:00'::timestamp as localtime, 'America/Chicago' AS tzone;
+---------------------+-----------------+
|      localtime      |      tzone      |
+---------------------+-----------------+
| 2030-02-26 10:00:00 | America/Chicago |
+---------------------+-----------------+
unutbu=# select '2018-11-04 00:59:59'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-11-04 05:59:59 |
+---------------------+
然后,您可以使用

unutbu=# select '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2030-02-26 16:00:00 |
+---------------------+
查询返回UTC日期时间,
2030-02-26 16:00:00
,它对应于芝加哥的
2030-02-26 10:00:00
localtime

在时区使用
会将时区规则的应用延迟到进行查询时,而不是插入
时间戳时


时间戳上使用
在时区
将日期时间定位到给定时区,但报告用户时区中的日期时间。 在
时间戳
上使用
在时区
将日期时间转换为给定的时区,然后删除偏移量,从而返回
时间戳
。 上面,
在时区
使用了两次:首先是本地化时间戳
,然后将返回的时间戳转换为新的时区(UTC)。结果是UTC中的
时间戳

下面是一个示例,演示了时区的
时间戳
上的行为:

unutbu=# SET timezone = 'America/Chicago';
unutbu=# SELECT '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago';
+------------------------+
|        timezone        |
+------------------------+
| 2030-02-26 10:00:00-06 |
+------------------------+

unutbu=# SET timezone = 'America/Los_Angeles';
unutbu=# SELECT '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago';
+------------------------+
|        timezone        |
+------------------------+
| 2030-02-26 08:00:00-08 |
+------------------------+
2030-02-26 10:00:00-06
2030-02-26 08:00:00-08
是相同的日期时间,但在不同的用户时区中报告。这表明芝加哥的上午10点是洛杉矶的上午8点(使用当前时区定义):


除了在时区两次使用
之外,还有一种选择,那就是使用
UTC
。那你可以用

select localtime AT TIME ZONE tzone
请注意,这样做时,将返回
时间戳
,而不是
时间戳


请注意,存储本地时间可能会有问题,因为可能存在不存在的时间和不明确的时间。 例如,
2018-03-11 02:30:00
America/Chicago
中是不存在的本地时间。Postgresql规范化不存在的本地时间,假定它是指夏时制(DST)开始后的相应时间(好像有人忘记将时钟向前拨):

本地时间不明确的一个例子是
2018-11-04 01:00:00
中的
America/Chicago
。由于DST,它发生两次。Postgresql通过在DST结束后选择更晚的时间来解决此歧义:

unutbu=# select '2018-11-04 01:00:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-11-04 07:00:00 |
+---------------------+
请注意,这意味着无法通过在
America/Chicago
时区中存储本地时间来引用
2018-11-04 06:00:00 UTC

unutbu=# select '2030-02-26 10:00:00'::timestamp as localtime, 'America/Chicago' AS tzone;
+---------------------+-----------------+
|      localtime      |      tzone      |
+---------------------+-----------------+
| 2030-02-26 10:00:00 | America/Chicago |
+---------------------+-----------------+
unutbu=# select '2018-11-04 00:59:59'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-11-04 05:59:59 |
+---------------------+

像日历事件一样思考。UTC对我们来说没有意义that@DanielA.White谢谢具体信息应修改问题描述,然后;您可以更新它以指定这些值的用途吗?