2012 年 11 月 4 日,美国冬令时从凌晨 2 点调整到凌晨 1 点。例如,CDT 凌晨 2 点变成了 CST 凌晨 1 点。
这意味着在凌晨 1:32“发生了两次”:CDT 1:32(纪元 1352010776642)和一个小时后的 CST 1:32(纪元 1352014376642)。
是否有可能以某种方式在 PostgreSQL 中以普通 timestamp
类型区分两者?我们观察到,在 1:32 CDT,我们的应用程序将日期存储为 1352014376642(“第二次出现”)。
最佳答案
据我所知,没有。
TIMESTAMP WITHOUT TIME ZONE
("plain timestamp
) 就像您使用的那样直接存储本地时间,同样不存储关联的 UTC 偏移量或时区。它是本地的时间,所以除非您存储了与该本地时间关联的时区,否则它可能是许多不同时刻之一。
转换后无法区分 '2012-01-01 11:00 +0800'
和 '2012-01-01 11:00 +0700'
到 timestamptz
并存储。因此,如果您有一个 DST 转换导致一个小时在不同的时区重播,您将无法重建该信息。证人:
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
字段不是用于识别离散时间点的正确类型,所以你是 SOL。
顺便说一句,TIMESTAMP WITH TIME ZONE
使用 timezone
设置将时间戳转换为 UTC 进行存储,然后返回本地时区进行检索。它描述了一个瞬间(大致上,请参阅末尾的链接)。这意味着在 timestamptz
中,像 timestamp
丢失了原始时区。这令人困惑并且似乎与数据类型的名称相矛盾。显然,这就是标准,所以无论它是否愚蠢,我们都坚持使用它。要区分时间戳,您还需要存储关联的 UTC 偏移量。最好将其命名为 TIMESTAMP WITH TIME ZONE CONVERSION
。
这使得 timestamptz
适合存储离散的时间点,但不太适合存储事件在现实世界本地时间发生的时间。同时存储 UTC 偏移量和/或 tzname。
参见:
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 偏移量相结合。
也就是说,you can't rely on the clock not to double up timestamps or otherwise be bizarre无论如何,因此有必要拥有对时间非常稳健并且不相信它有多大意义的代码。
关于postgresql - Postgres 可以区分时间戳和夏令时吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13231557/