TIMESTAMP WITHOUT TIME ZONE 和 TIMESTAMP WITH TIME ZONE (TIMESTAMPTZ) 之间的区别如果考虑它们的名称,可能会非常难以理解。 (事实上,规范似乎很混乱,以至于各种 RDBMS 以不同的方式实现它。)
在 PostgreSQL 中,两种类型都存储值的时区,但 TIMESTAMPTZ 将值存储为基于 UTC 参考的精确时刻,而 TIMESTAMP WITHOUT TIME ZONE 始终是相对的。
- 查询时,
TIMESTAMPTZ 将被调整为表示与最初存储的时间相同的时刻(在世界的任何地方),就像它在客户端配置的当前时区中的时刻一样。
-
TIMESTAMP WITHOUT TIME ZONE 将始终是相对于客户端配置的时区的相同值,即使您查询它的时区不同:2013-11-03 03:00:00 表示的瞬间将是不明确的并且取决于客户端设置。
您大概使用了“时区”列(P 或 M)和 TIMESTAMP WITHOUT TIME ZONE 来补偿 输入 值中的歧义。
原则上,如果您与存储时间戳的相对时区处于相同的相对时区,则应该返回相同的值,因此,如果您将客户端设置为 US/Pacific 时区,并且如果您已经将2013-11-03 03:00:00 存储在您的P 时区,您应该得到2013-11-03 03:00:00。但是,这仅在相对值没有歧义时才有效。
您的第一个示例中的问题是已经存在一些歧义:
时间戳:2013-11-03 01:00:00 时区:“P”将变为:2013-11-03
01:00:00-07
2013-11-03 01:00:00 可以代表US/Pacific 时区中的两个不同时刻,因此仅使用2013-11-03 01:00:00 和"P",您已经丢失了无法恢复的信息。
如果您只是希望它根据当时的 DST 设置在“-08”和“-07”之间切换,这将自动为您完成,但您应该使用TIMESTAMPTZ in首先,准确地说是您所代表的时间点。
这是一个保留初始时区的示例,因此您可以看到“-08”和“-07”之间的变化:
SET time zone 'US/Pacific';
SELECT t AS "Date/Time for US/Pacific",
t AT time zone 'UTC' "Date/Time in UTC"
FROM (VALUES
('2013-11-03 00:00:00-07'::timestamptz),
('2013-11-03 01:00:00-07'::timestamptz),
('2013-11-03 02:00:00-07'::timestamptz),
('2013-11-03 03:00:00-07'::timestamptz)) AS v(t);
结果:
| DATE/TIME FOR US/PACIFIC | DATE/TIME IN UTC |
|--------------------------|---------------------|
| 2013-11-03 00:00:00-07 | 2013-11-03 07:00:00 |
| 2013-11-03 01:00:00-07 | 2013-11-03 08:00:00 |
| 2013-11-03 01:00:00-08 | 2013-11-03 09:00:00 |
| 2013-11-03 02:00:00-08 | 2013-11-03 10:00:00 |
很遗憾,仅使用您的两个字段无法处理 DST 更改。
当然值得阅读Date/Time types section of the PostgreSQL manual,同时关注AT TIME ZONE documentation中表格的“返回类型”列,以便更好地理解这些问题。