我只是花了一个小时的绝望,这两个表达的结果有差异:
db=# SELECT '2012-01-18 1:0 CET'::timestamptz AT TIME ZONE 'UTC'
,'2012-01-18 1:0 Europe/Vienna'::timestamptz AT TIME ZONE 'UTC';
timezone | timezone
---------------------+---------------------
2012-08-18 00:00:00 | 2012-08-17 23:00:00
显然,第二个表达式根据DST规则扣除两个小时,其中第一个表达式仅使用标准偏移量。
我检查了这两个时区名称的目录。他们都在那里,看起来一样:
db=# SELECT * FROM pg_timezone_names WHERE name IN ('CET', 'Europe/Vienna');
name | abbrev | utc_offset | is_dst
---------------+--------+------------+--------
Europe/Vienna | CEST | 02:00:00 | t
CET | CEST | 02:00:00 | t
我咨询了PostgreSQL manual about time zones:
PostgreSQL允许您以三种不同的形式指定时区:
全时区名称,例如America / New_York。已识别的时区名称列在pg_timezone_names视图中 (见45.67节)。 PostgreSQL使用广泛使用的zoneinfo时间 为此目的的区域数据,因此也可以识别相同的名称 很多其他软件。
时区缩写,例如PST。 与全时相比,此类规范仅定义了与UTC的特定偏移量 区域名称可能意味着一组夏令时过渡日期 规则也是如此。公认的缩写列于 pg_timezone_abbrevs视图(参见第45.66节)。你不能设置 配置参数timezone或log_timezone到时区 缩写,但您可以在日期/时间输入值中使用缩写 以及AT TIME ZONE操作员。
大胆强调我的。
那为什么会有区别?
关于Debian Squeeze的PostgreSQL 9.1.4(来自http://backports.debian.org/debian-backports的标准挤压后退)
本地timezone
设置默认为系统区域设置de_AT.UTF-8
,但与示例无关。
SELECT version();
version
-------------------------------------------------------------------------------------------------------
PostgreSQL 9.1.4 on x86_64-unknown-linux-gnu, compiled by gcc-4.4.real (Debian 4.4.5-8) 4.4.5, 64-bit
SHOW timezone_abbreviations;
timezone_abbreviations
------------------------
Default
..我(假设)加载此文件中的缩写: /usr/share/postgresql/9.1/timezonesets/Default
时区名CET
来自我,我感到很茫然。但显然它在我的装置中存在。 quick test on sqlfiddle显示相同的结果。
我在具有类似设置的两台不同服务器上进行了测试。还有PostgreSQL 8.4。在所有这些pg_timezone_names
中找到'CET'作为时区名称。
答案 0 :(得分:4)
在我发布这个之后,我运行了另一个查询来检查怀疑:
SELECT * FROM pg_timezone_abbrevs
WHERE abbrev IN ('CEST', 'CET');
abbrev | utc_offset | is_dst
--------+------------+--------
CEST | 02:00:00 | t
CET | 01:00:00 | f
事实证明,还时区缩写名为CET
(这是有道理的,“CET”是缩写)。似乎PostgreSQL选择了全名的缩写。因此,即使我在时区名称中找到CET
,表达式'2012-01-18 1:0 CET':: timestamptz也会根据时间上略有不同的时间规则进行解释zone 缩写。
SELECT '2012-01-18 1:0 CEST'::timestamptz(0)
,'2012-01-18 1:0 CET'::timestamptz(0)
,'2012-01-18 1:0 Europe/Vienna'::timestamptz(0);
timestamptz | timestamptz | timestamptz
------------------------+------------------------+------------------------
2012-01-18 00:00:00+01 | 2012-01-18 01:00:00+01 | 2012-01-18 01:00:00+01
SELECT '2012-08-18 1:0 CEST'::timestamptz(0)
,'2012-08-18 1:0 CET'::timestamptz(0)
,'2012-08-18 1:0 Europe/Vienna'::timestamptz(0);
timestamptz | timestamptz | timestamptz
------------------------+------------------------+------------------------
2012-08-18 01:00:00+02 | 2012-08-18 02:00:00+02 | 2012-08-18 01:00:00+02
我在时区名称中找到10个时区缩写,并且无法理解为什么那些。目的是什么?
其中,由于DST设置,时间偏移(utc_offset
)在四种情况下不一致:
SELECT n.*, a.*
FROM pg_timezone_names n
JOIN pg_timezone_abbrevs a ON a.abbrev = n.name
WHERE n.utc_offset <> a.utc_offset;
name | abbrev | utc_offset | is_dst | abbrev | utc_offset | is_dst
------+--------+------------+--------+--------+------------+--------
CET | CEST | 02:00:00 | t | CET | 01:00:00 | f
EET | EEST | 03:00:00 | t | EET | 02:00:00 | f
MET | MEST | 02:00:00 | t | MET | 01:00:00 | f
WET | WEST | 01:00:00 | t | WET | 00:00:00 | f
在这些情况下,人们可能会被愚弄(就像我一样),查找tz 名称并找到实际未应用的时间偏移。这是一个不幸的设计 - 如果不是错误,至少是文档错误。
我在手册中找不到有关如何解决时区名称和缩写之间的歧义的问题。显然缩写优先。
Appendix B.1. Date/Time Input Interpretation提到查找时区缩写,但仍然不清楚如何识别时区名称以及哪些优先级如果是暧昧的令牌。
如果令牌是文本字符串,请与可能的字符串匹配:
将令牌的二进制搜索表查找作为时区缩写。
嗯,这句话中有一点点暗示,缩写首先出现,但没有确定的。此外,两个表格中都有一列abbrev
,pg_timezone_names
和pg_timezone_abbrevs
......
答案 1 :(得分:2)
时区缩写不包括夏令时(DST)转换规则的原因是它们倾向于暗示状态。在美国中西部地区,我们在冬季的CST(中央标准时间)以及今年剩余时间的CDT(中部夏令时)。有些异常区域没有使用DST,所以它变得复杂。
PostgreSQL没有维护自己的时区数据,尽管它为那些没有提供它的操作系统在每个版本中打包最新的Olson时区数据。通常,PostgreSQL将使用来自操作系统的时区信息,因此如果您遇到问题,请确保您拥有最新版本。
作为参考,今天在我的系统上,我得到了这些结果:
test=# SELECT '2012-01-18 1:0 CET'::timestamptz AT TIME ZONE 'UTC' test-# ,'2012-01-18 1:0 Europe/Vienna'::timestamptz AT TIME ZONE 'UTC'; timezone | timezone ---------------------+--------------------- 2012-01-18 00:00:00 | 2012-01-18 00:00:00 (1 row) test=# SELECT * FROM pg_timezone_names WHERE name IN ('CET', 'Europe/Vienna'); name | abbrev | utc_offset | is_dst ---------------+--------+------------+-------- CET | CEST | 02:00:00 | t Europe/Vienna | CEST | 02:00:00 | t (2 rows)
test=# SELECT * FROM pg_timezone_abbrevs test-# WHERE abbrev IN ('CEST', 'CET'); abbrev | utc_offset | is_dst --------+------------+-------- CEST | 02:00:00 | t CET | 01:00:00 | f (2 rows) test=# SELECT '2012-01-18 1:0 CEST'::timestamptz(0) test-# ,'2012-01-18 1:0 CET'::timestamptz(0) test-# ,'2012-01-18 1:0 Europe/Vienna'::timestamptz(0); timestamptz | timestamptz | timestamptz ------------------------+------------------------+------------------------ 2012-01-17 17:00:00-06 | 2012-01-17 18:00:00-06 | 2012-01-17 18:00:00-06 (1 row) test=# SELECT '2012-08-18 1:0 CEST'::timestamptz(0) test-# ,'2012-08-18 1:0 CET'::timestamptz(0) test-# ,'2012-08-18 1:0 Europe/Vienna'::timestamptz(0); timestamptz | timestamptz | timestamptz ------------------------+------------------------+------------------------ 2012-08-17 18:00:00-05 | 2012-08-17 19:00:00-05 | 2012-08-17 18:00:00-05 (1 row)