区域名称PostgreSQL错误的“ AT TIME ZONE”?


12

我在回答这个stackoverflow问题,发现奇怪的结果:

 select * from  pg_timezone_names where name = 'Europe/Berlin' ;
     name      | abbrev | utc_offset | is_dst 
---------------+--------+------------+--------
 Europe/Berlin | CET    | 01:00:00   | f

和下一个查询

select id, 
  timestampwithtimezone, 
  timestampwithtimezone at time zone 'Europe/Berlin' as berlin, 
  timestampwithtimezone at time zone 'CET' as cet 
from data ;
 id  | timestampwithtimezone  |       berlin        |         cet         
 -----+------------------------+---------------------+---------------------
 205 | 2012-10-28 01:30:00+02 | 2012-10-28 01:30:00 | 2012-10-28 00:30:00
 204 | 2012-10-28 02:00:00+02 | 2012-10-28 02:00:00 | 2012-10-28 01:00:00
 203 | 2012-10-28 02:30:00+02 | 2012-10-28 02:30:00 | 2012-10-28 01:30:00
 202 | 2012-10-28 02:59:59+02 | 2012-10-28 02:59:59 | 2012-10-28 01:59:59
 106 | 2012-10-28 02:00:00+01 | 2012-10-28 02:00:00 | 2012-10-28 02:00:00

我正在使用PostgreSQL 9.1.2和ubuntu 12.04。
刚刚检查了8.2.11的结果是否相同。

根据文档,我使用名称还是缩写都没有关系。

这是一个错误吗?
难道我做错了什么?
有人可以解释这个结果吗?

编辑 对于CET不是欧洲/柏林的评论。

我只是从pg_timezone_names中选择值。

select * from  pg_timezone_names  where abbrev ='CEST';
 name | abbrev | utc_offset | is_dst 
------+--------+------------+--------

select * from  pg_timezone_names  where abbrev ='CET';
        name         | abbrev | utc_offset | is_dst 
---------------------+--------+------------+--------
 Africa/Tunis        | CET    | 01:00:00   | f
 Africa/Algiers      | CET    | 01:00:00   | f
 Africa/Ceuta        | CET    | 01:00:00   | f
 CET                 | CET    | 01:00:00   | f
 Atlantic/Jan_Mayen  | CET    | 01:00:00   | f
 Arctic/Longyearbyen | CET    | 01:00:00   | f
 Poland              | CET    | 01:00:00   | f
 .....

在冬季,欧洲/柏林为+01。夏季为+02。

EDIT2 在2012-10-28时区从夏令时更改为冬季时间2:00。
这两个记录在欧洲/柏林具有相同的价值:

204 | 2012-10-28 02:00:00+02 | 2012-10-28 02:00:00 | 2012-10-28 01:00:00
106 | 2012-10-28 02:00:00+01 | 2012-10-28 02:00:00 | 2012-10-28 02:00:00

这表明如果我对大数据范围(夏季时间和冬季时间)使用缩写(CET或CEST)之一,则对于某些记录而言,结果将是错误的。如果我使用“欧洲/柏林”,将会很好。

我将系统时间更改为“ 2012-01-17”,并且pg_timezone_names也已更改。

select * from  pg_timezone_names  where name ='Europe/Berlin';
     name      | abbrev | utc_offset | is_dst 
---------------+--------+------------+--------
 Europe/Berlin | CEST   | 02:00:00   | t

1
可以肯定的2012-10-28 01:30:00是CEST,而不是CET。
dezso 2012年

1
据我所知CET没有 Europe/Berlin -至少在DST次不行。
a_horse_with_no_name 2012年

Answers:


9

实际上,文档清楚地表明时区名称和缩写的行为会有所不同。

简而言之,这就是缩写和全名之间的区别:缩写始终代表与UTC的固定偏移量,而大多数全名暗示着当地的夏时制规则,因此有两个可能的UTC偏移量。参考

FWIW,同样的参考文献也说

我们不建议使用带时区的时间类型(尽管PostgreSQL支持遗留应用程序并符合SQL标准)。


6

而且这还不是要点!前一段时间,我遇到了一个非常类似的问题

时区缩写的主要缺点已经在此处提出:它们未考虑DST(夏令时)。主要优点:简单性带来卓越的性能。考虑DST规则会使时区名称比较。时区缩写很简单,是符号时间偏移,时区名称受一组不断变化的规则的约束。我在SO上的这个相关答案中运行了基准测试,差异非常明显。但是,当应用于集合时,通常需要使用时区名称来覆盖每行可能不同的DST状态(以及历史差异)。

我们正在谈论CET。真正棘手的部分是“CET”不仅是(显然)一个时区缩写,它也是一个时区名称,至少根据我的安装(PostgreSQL的9.1.6在Debian挤压与区域“de_AT.UTF-8 ”以及到目前为止我所看到的所有其他内容。我提到这些细节,因为Postgres使用基础操作系统的语言环境信息(如果有)。

你自己看:

SELECT * FROM pg_timezone_names WHERE name = 'CET';

SELECT * FROM pg_timezone_abbrevs WHERE abbrev = 'CET';

SQL提琴。

Postgres选择全名的缩写。因此,即使我在时区名称中找到了CET ,该表达式'2012-01-18 01:00 CET'::timestamptz也会根据时区缩写的微妙规则进行解释。

如果那不是一柄脚步枪,我不知道这是什么。

为避免歧义,请使用时区名称“欧洲/柏林”(在我的情况下为“欧洲/维也纳”,实际上是相同的,除了历史差异之外)。在我上面提到密切相关的问题下找到有关该主题的更多详细信息。

最后,我要表达我对DST的谐音概念的深切鄙视。应该从存​​在中删除它,再也不要谈论它。


3

检查一下:

select  
    '2012-10-28 02:30:00+02'::timestamp with time zone at time zone 'Europe/Berlin' as berlin,
    '2012-10-28 02:30:00+02'::timestamp with time zone at time zone 'CET' as cet,
    '2012-10-28 02:30:00+02'::timestamp with time zone at time zone 'CEST' as cest

+02 是柏林的CEST,而不是CET。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.