关于postgresql:Postgres数据库中特有的时区处理

Peculiar time zone handling in a Postgres database

我的环境

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

问题

查询具有特定时区设置的current_date(或current_time)似乎会产生与我的信念不一致的结果。

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

1
2
SET TIME ZONE 'UTC+01';
SELECT CURRENT_DATE, CURRENT_TIME;
1
2
3
4
5
+------------+--------------------+
| DATE       | timetz             |
+------------+--------------------+
| 2016-11-24 | 22:00:01.581552-01 |
+---------------------------------+

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

1
2
SET TIME ZONE 'CET';
SELECT CURRENT_DATE, CURRENT_TIME;

要么

1
2
SET TIME ZONE 'Europe/Paris';
SELECT CURRENT_DATE, CURRENT_TIME;
1
2
3
4
5
+------------+--------------------+
| DATE       | timetz             |
+------------+--------------------+
| 2016-11-25 | 00:00:01.581552-01 |
+---------------------------------+

有正确的时间和日期。

那里发生了什么?
对我来说为时已晚,我混淆了UTC+1UTC-1还是有更大的东西让我忽略?
AWS RDS是否在此中发挥作用?


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

Another issue to keep in mind is that in POSIX time zone names,
positive offsets are used for locations west of Greenwich. Everywhere
else, PostgreSQL follows the ISO-8601 convention that positive
timezone offsets are east of Greenwich.

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

  • AT TIME ZONE和UTC偏移的奇数

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

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

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

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

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

We do not recommend using the type time with time zone (though it is
supported by PostgreSQL for legacy applications and for compliance
with the SQL standard)

考虑:

1
2
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
1
2
3
     plus_wrong      |     minus_right    
---------------------+---------------------
 2016-06-05 23:00:00 | 2016-06-06 01:00:00
1
2
3
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!
1
2
3
     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
1
2
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
1
2
3
 paris_summer         | paris_winter
----------------------+----------------------
 2016-06-06 02:00:00  | 2016-01-01 01:00:00  -- always right

有关:

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

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

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