在PostgreSQL中代表未来的时间



我已经有条件将过去作为UTC存储在数据库中,因为实际上是在事件发生的情况下。对于将来的日期,我将使用特定的时区存储它,以避免更改,例如LEAP秒或时区规则更改。

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

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

认为[它]像日历事件。UTC对此没有意义

听起来您要在某个时区存储 localtime 。在这种情况下,将timestamp(无时间区域)和timezone存储在单独的列中。

例如,假设您想录制一个将于2030年2月26日上午10点在芝加哥举行的活动它必须在上午10点 localtime 不管该日期有效的时区规则。

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

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 DateTime,2030-02-26 16:00:00,与芝加哥的2030-02-26 10:00:00 Localtime相对应。

使用AT TIME ZONE 延迟了时区规则的应用何时进行查询,而不是插入timestamptz时。


timestamp上使用AT TIME ZONE将日期时间定位于给定的时区,但 Reports 用户的时区中的日期时间。在timestamptz上使用AT TIME ZONE将日期时间转换为给定时区,然后删除偏移,从而返回timestamp。以上,AT TIME ZONE使用两次:首先将timestamp定位,然后将返回的timestamptz转换为新时区(UTC)。结果是UTC中的timestamp

这是一个例子,在timestamp S上演示了AT TIME ZONE的行为:

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-062030-02-26 08:00:00-08是相同的数据,但在不同的用户时区报告。这显示在芝加哥上午10点在洛杉矶上午8点(使用当前时区定义):

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的替代方法是将用户时区设置为UTC。那么您可以使用

select localtime AT TIME ZONE tzone

请注意,这样做时,返回timestamptz而不是timestamp


注意,存储本地时间可能会出现问题,因为可能存在不存在的时间和模棱两可的时间。例如,2018-03-11 02:30:00America/Chicago中不存在的本地时间。PostgreSQL假设它是指日光储蓄时间(DST)已经开始(好像有人忘记忘记将其时钟设置为前进),从而使不存在的本地时间归一化。

unutbu=# 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)

模棱两可的本地时间的示例是America/Chicago中的2018-11-04 01:00:00。由于DST,它发生了两次。DST结束后,PostgreSQL通过选择以后的时间来解决这种歧义:

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 '2018-11-04 00:59:59'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-11-04 05:59:59 |
+---------------------+

特别是,如果要保护自己免受未来的Zune更改,则应使用timestamp with time zone

postgresql内部存储自2000-01-01-01 00:00以来的微秒数量,该数量可容纳时区的变化。如果您继续更新PostgreSQL,它将始终为您的会话时区正确显示该绝对值。

postgresql中没有leap秒的规定。

对于将来的日期,我将使用特定的时区存储它,以避免更改,例如leap秒或时区规则更改。

似乎落后。UTC的主要优势在其他时区域是容易出乎意料的未来变化:UTC仅在已知的日历年的有限点上引入LEAP秒;而且没有频繁的政治偏移变化。

在某些本地管理的时区中存储值使这些值更容易容易出现(与UTC相比)到任意,不可预测的未来含义变化。

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

对于PostgreSQL,这意味着优先使用TIMESTAMP WITH TIME ZONE

相关内容

  • 没有找到相关文章

最新更新