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 allows you to specify time zones in three different forms:
A full time zone name,for example America/New_York. The recognized time zone names are listed in the pg_timezone_names view
(see Section 45.67). Postgresql uses the widely-used zoneinfo time
zone data for this purpose,so the same names are also recognized by
much other software.A time zone abbreviation,for example PST. Such a specification merely defines a particular offset from UTC,in contrast to full time
zone names which can imply a set of daylight savings transition-date
rules as well. The recognized abbreviations are listed in the
pg_timezone_abbrevs view (see Section 45.66). You cannot set the
configuration parameters timezone or log_timezone to a time zone
abbreviation,but you can use abbreviations in date/time input values
and with the AT TIME ZONE operator.
大胆的重点我的.
为什么差异呢?
我的设置(添加了更多细节)
> Debian Squeeze上的Postgresql 9.1.4(从http://backports.debian.org/debian-backports开始的标准挤压后退)
>本地时区设置默认为系统区域设置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来自哪里.但显然它在我的装置中存在. A quick test on sqlfiddle显示相同的结果.
我在具有类似设置的两个不同服务器上测试还有Postgresql 8.4.在所有pg_timezone_names中找到’CET’作为时区名称.
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也会根据时区缩写的细微不同规则进行解释.
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名称并找到实际未应用的时间偏移.这是一个不幸的设计 – 如果不是一个bug,至少是一个文档错误.
我没有在手册中找到有关如何解决时区名称和缩写之间的歧义的问题.显然缩写优先.
Appendix B.1. Date/Time Input Interpretation提到了时区缩写的查找,但仍然不清楚如何识别时区名称,以及在模糊标记的情况下哪些具有优先级.
If the token is a text string,match up with possible strings:
Do a binary-search table lookup for the token as a time zone abbreviation.
嗯,这句话中有一点点暗示,缩写首先出现,但没有确定性.此外,两个表中都有一个列缩写,pg_timezone_names和pg_timezone_abbrevs …