Postgres能够区分带夏令时的时间戳吗?

4
在美国,于11/4/12时钟从2AM调整为1AM以适应冬令时。例如,2AM CDT变成了1AM CST。
这意味着在那天凌晨1:32,“发生了两次”:1:32 CDT(时间戳1352010776642),一个小时后是1:32 CST(时间戳1352014376642)。
在PostgreSQL中,是否有可能以普通的时间戳类型区分这两个时间?我们观察到,在CDT 1:32时,我们的应用程序将日期存储为1352014376642(“第二次出现”)。

你引用的纪元值来自哪里? - Craig Ringer
我实际上是从Java中获取它们的,尽管这并不重要。 - Konrad Garus
我的意思是“你是如何推导出它们的”,我表达得不好。我想你使用了带时区的时间戳并转换为纪元时间,对吗?回答已更新。 - Craig Ringer
1个回答

2
据我所知,不是这样的。
像您使用的“不带时区的时间戳”(“plain timestamp”)一样,直接存储本地时间,而不存储关联的UTC偏移量或时区。它是本地时间,因此,除非您存储了与该本地时间相关联的时区,否则它可能是许多不同瞬间中的一个。
一旦转换为“带时区的时间戳”(“timestamptz”)并存储,就无法区分“2012-01-01 11:00 +0800”和“2012-01-01 11:00 +0700”。因此,如果夏令时转移导致在不同的时区重播一个小时,您将无法重构该信息。请看:
regress=> select extract(epoch from '2012-01-01 11:00 +0800'::timestamp),
                 extract(epoch from '2012-01-01 11:00 +700'::timestamp);
 date_part  | date_part  
------------+------------
 1325415600 | 1325415600
(1 row)

正如您所看到的,时区被忽略了;它被剥离并丢弃了。时间戳字段不是用于识别时间点的正确类型,因此您无法解决这个问题。
顺便提一下,TIMESTAMP WITH TIME ZONE 会将时间戳转换为协调世界时(UTC)进行存储,并使用 timezone 设置将其转换回本地时区进行检索。它描述了一个瞬间(大致如此,请参见末尾的链接)。这意味着在 timestamptz 中,就像在 timestamp 中一样,原始时区已经丢失。这很令人困惑,似乎与数据类型的名称相矛盾。显然,这就是标准规定,所以无论是否愚蠢,我们都必须遵守它。要区分时间戳,您还需要存储相关的UTC偏移量。最好将其命名为TIMESTAMP WITH TIME ZONE CONVERSION
这使得timestamptz非常适合存储时间点,但不适合存储事件发生的实际本地时间。请同时存储UTC偏移量和/或时区名称。
请参阅:
regress=> select extract(epoch from '2012-01-01 01:00 CST'::timestamptz),
                 extract(epoch from '2012-01-01 02:00 CDT'::timestamptz);
 date_part  | date_part  
------------+------------
 1325401200 | 1325401200

遗憾的是,没有一种数据类型将TIMESTAMP WITH TIME ZONE与记录转换前的TZ偏移量的内部UTC偏移量结合起来。
话虽如此,您不能依赖时钟不会重复时间戳或以其他方式变得奇怪,因此有必要编写非常强大的关于时间的代码,并且不信任它会有多大意义。

有趣。所以带时区的timestamptz本质上是一个纪元时间,比timestamp更加清晰(无歧义)。感谢你的回答,我担心会是这种情况。 - Konrad Garus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接