我已经习惯于将过去的日期作为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的偏移量。如果更改时区规则,则该列将不会反映出来。
在这种情况下推荐什么?
答案 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 ZONE
在timestamp
上的行为:
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点(使用当前时区定义):
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:00
是America/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
。