代表PostgreSQL的未来时间

问题描述 投票:0回答:4

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

Postgres有timestamp with timezone,但在封面下,它将其存储为UTC,推断指定的时区是UTC的偏移量。如果时区规则要更改,则不会反映在列中。

在这种情况下推荐什么?

postgresql datetime timezone timestamp-with-timezone
4个回答
1
投票

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

听起来你想要存储一个关于某个时区的本地时间。在这种情况下,将timestamp(没有时区)和timezone存储在单独的列中。

例如,假设您要记录将于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 |
+---------------------+-----------------+

然后,您可以使用找到事件的UTC日期时间

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日期时间qazxsw poi,它对应于芝加哥当地时间的qazxsw poi。

使用2030-02-26 16:00:00将时区规则的应用延迟到查询时,而不是插入2030-02-26 10:00:00时。


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

这是一个例子,展示了timestamptztimestamps上的行为:

AT TIME ZONE

timestampunutbu=# 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 | +------------------------+ 是相同的日期时间,但在不同的用户时区报告。这显示芝加哥上午10点是洛杉矶上午8点(使用当前时区定义):

2030-02-26 10:00:00-06

使用2030-02-26 08:00:00-08两次的替代方法是unutbu=# SELECT '2030-02-26 10:00:00-06'::timestamptz AT TIME ZONE 'America/Los_Angeles'; +---------------------+ | timezone | +---------------------+ | 2030-02-26 08:00:00 | +---------------------+ AT TIME ZONE。然后你可以使用

set the user timezone

请注意,当这样做时,返回UTC而不是select localtime AT TIME ZONE tzone


请注意,存储本地时间可能会有问题,因为可能存在不存在的时间和不明确的时间。例如,timestamptztimestamp中不存在的当地时间。 Postgresql通过假设它引用夏令时(DST)开始后的相应时间来规范化不存在的本地时间(就好像有人忘记设置时钟前进一样):

2018-03-11 02:30:00

当地模糊不清的一个例子是America/Chicagounutbu=# select '2018-03-11 02:30:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC'; +---------------------+ | timezone | +---------------------+ | 2018-03-11 08:30:00 | +---------------------+ (1 row) unutbu=# select '2018-03-11 03:30:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC'; +---------------------+ | timezone | +---------------------+ | 2018-03-11 08:30:00 | +---------------------+ (1 row) 。由于DST,它会发生两次。 Postgresql通过选择DST结束后的较晚时间来解决这种歧义:

2018-11-04 01:00:00

请注意,这意味着无法通过在America/Chicago时区存储localtimes来引用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 | +---------------------+

2018-11-04 06:00:00 UTC

0
投票

特别是如果你想保护自己免受未来时间的zune变化,你应该使用America/Chicago

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

PostgreSQL中没有闰秒的规定。


0
投票

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

这看起来很落后。 UTC优于其他时区的主要优势在于它不太容易出现意外的未来变化:UTC仅在日历年的已知有限点引入闰秒;而且没有频繁的政治强制抵消变化。

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

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

对于PostgreSQL,这意味着更喜欢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 | +---------------------+

© www.soinside.com 2019 - 2024. All rights reserved.