代表PostgreSQL中的未来时间

时间:2019-02-27 03:43:17

标签: postgresql datetime timezone timestamp-with-timezone

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

Postgres具有conf = { '/': { 'tools.sessions.on': True, 'tools.staticdir.root': os.path.abspath(os.getcwd()) }, '/css': { 'tools.staticdir.on': True, 'tools.staticdir.dir': './css'}, '/img': { 'tools.staticdir.on': True, 'tools.staticdir.dir': './img'}, '/js': { 'tools.staticdir.on': True, 'tools.staticdir.dir': './js'}, 'global': { 'environment': 'production', 'log.screen': True, 'server.socket_host': '127.0.0.1', 'server.socket_port': 8080, 'engine.autoreload_on': True, }} ,但在幕后,它将其存储为UTC,从而推断指定的时区是UTC的偏移量。如果更改时区规则,则该列将不会反映出来。

在这种情况下推荐什么?

3 个答案:

答案 0 :(得分:1)

  

将其视为日历事件。 UTC对此没有任何意义

听起来好像您想存储相对于特定时区的 localtime 。 在这种情况下,请将timestamp(无时区)和timezone存储在单独的列中。

例如,假设您要记录一个事件,该事件将在2030年2月26日上午10点在芝加哥发生 并且该时间必须是当地时间上午10点(em),而不管该日期生效的时区规则。

如果数据库存储的时间戳不带时区:

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日期时间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被使用了两次:首先对timestamp进行本地化,然后将返回的timestamptz转换为新时区(UTC)。结果是UTC中的timestamp

以下是一个示例,展示了AT TIME ZONEtimestamp上的行为:

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的另一种方法是将set the user timezone转换为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)

一个不明确的本地时间示例是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 |
+---------------------+

请注意,这意味着无法通过在2018-11-04 06:00:00 UTC时区中存储本地时间来引用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 |
+---------------------+

答案 1 :(得分:0)

尤其是,如果您想保护自己免受将来时间zune更改的影响,则应使用timestamp with time zone

PostgreSQL内部存储自2000年1月1日00:00:00以来的微秒数,这对于时区更改是安全的。如果您继续更新PostgreSQL,它将始终在您的会话时区正确显示该绝对值。

PostgreSQL中没有规定leap秒。

答案 2 :(得分:0)

  

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

那似乎倒退了。 UTC与其他时区相比的主要优势 容易发生意外的未来变化:UTC仅在日历年的已知有限点引入leap秒;而且没有任何频繁的政治规定的补偿要求变动。

在一些本地管理的时区中存储值会使这些值更倾向于(与UTC相比)将来的任意,不可预测的含义变化。

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

对于PostgreSQL,这意味着更喜欢TIMESTAMP WITH TIME ZONE