Postgres 数据库中的特殊时区处理



我的环境

我在法国巴黎(UTC+1CET)。
这是12am(00:00),我们在2016年11月25日
我的Postgres数据库托管在eu-west-1区域的Amazon Web Services(AWS RDS) 上。

A. 问题

查询具有特定时区集的current_date(或current_time)似乎提供的结果与...我的信念。

特别是,查询current_date在使用CET时区或UTC+1时区时会产生不同的结果。

SET TIME ZONE 'UTC+01';
select current_date, current_time;
+------------+--------------------+ |日期 |蒂姆兹 | +------------+--------------------+ |2016-11-24 |22:00:01.581552-01 | +---------------------------------+

不,那是昨天——两个小时前。


SET TIME ZONE 'CET';
select current_date, current_time;

SET TIME ZONE 'Europe/Paris';
select current_date, current_time;
+------------+--------------------+ |日期 |蒂姆兹 | +------------+--------------------+ |2016-11-25 |00:00:01.581552-01 | +---------------------------------+

有正确的时间和日期。

问题

这是怎么回事?
对我来说为时已晚,我混淆了UTC+1UTC-1还是我忽略了更大的事情? AWS RDS 是否在这方面发挥作用?

这个问题似乎与Amazon RDS无关:它与PostgreSQL使用的约定有关。在这种情况下,您的时区名称确实是向后移动的。你的意思是你写'UTC+01'.
从手册'UTC-01'

要记住的另一个问题是,在 POSIX 时区名称中, 正偏移用于格林威治以西的位置。到处 否则,PostgreSQL遵循ISO-8601约定,积极 时区偏移量位于格林威治以东

因此,用于SET TIME ZONE(以及相应的SHOW timezone显示)或AT TIME ZONE构造的时区字符串使用与timestamp(with time zone)文字中显示的相反的符号!这是ISO和SQL标准与POSIX之间非常不幸的分歧。(我认为POSIX是罪魁祸首。看:

  • 时区和 UTC 偏移量的奇数

  • 为什么PostgreSQL将数字UTC偏移量解释为POSIX而不是ISO-8601?

但是'CET''UTC-01'巴黎来说仍然可能是错误的,因为他们没有考虑夏令时的规则.
(夏令时是人类历史上最愚蠢的概念之一。

巴黎(与欧洲大部分地区一样)在冬季使用CET,在夏季使用CEST。你用'CET'的测试恰好在 11 月工作。如果你在夏天尝试同样的事情,你会得到错误的结果。

为了安全起见,请始终使用时区名称'Europe/Paris',它考虑了 DST 规则。通话费用更高。

如果您的时区设置暗示任何规则,该函数current_time会考虑 DST 规则。但'UTC-01'是一个普通的时间偏移。我从不使用数据类型time with time zonecurrent_time。手册再次:

我们不建议使用类型time with time zone(尽管它是 PostgreSQL 支持用于遗留应用程序和合规性 与SQL标准)

考虑:

SELECT '2016-06-06 00:00+0'::timestamptz AT TIME ZONE 'UTC+01' AS plus_wrong
, '2016-06-06 00:00+0'::timestamptz AT TIME ZONE 'UTC-01' AS minus_right
plus_wrong      |     minus_right     
---------------------+---------------------
2016-06-05 23:00:00 | 2016-06-06 01:00:00
SELECT '2016-01-01 00:00+0'::timestamptz AT TIME ZONE 'CET'    AS cet_winter
, '2016-06-06 00:00+0'::timestamptz AT TIME ZONE 'CEST'   AS cest_summer
, '2016-06-06 00:00+0'::timestamptz AT TIME ZONE 'CET'    AS cet_no_dst  -- CET wrong!
cet_winter      |     cest_summer     |     cet_no_dst      
---------------------+---------------------+---------------------
2016-01-01 01:00:00 | 2016-06-06 02:00:00 | 2016-06-06 01:00:00  -- wrong
SELECT '2016-06-06 00:00+0'::timestamptz AT TIME ZONE 'Europe/Paris' AS paris_summer
, '2016-01-01 00:00+0'::timestamptz AT TIME ZONE 'Europe/Paris' AS paris_winter
paris_summer         | paris_winter
----------------------+----------------------
2016-06-06 02:00:00  | 2016-01-01 01:00:00  -- always right

相关:

  • 在 Rails 和 PostgreSQL 中完全忽略时区

  • 具有相同属性的时区名称在应用于时间戳时会产生不同的结果

  • 数据类型为"带时区的时间戳"的时区存储

最新更新