我在x86_64-pc-linux-gnu上运行PostgreSQL 9.6.6,我的时区设置为'UTC'。
有谁知道为什么以下SELECT
声明的结果不同?
一个)
SELECT timezone('EST', '2017-12-21');
timezone
---------------------
2017-12-20 19:00:00
B)
SELECT timezone('-05', '2017-12-21');
timezone
---------------------
2017-12-21 05:00:00
根据pg_timezone_names
表-05
应该与EST
具有相同的偏移...任何想法?谢谢。
https://www.postgresql.org/docs/current/static/view-pg-timezone-names.html
视图pg_timezone_names提供SET TIMEZONE识别的时区名称列表
并进一步:
utc_offset interval UTC的偏移量(正值表示格林威治以东)
当你set timezone to 'EST'
- 你声明你的客户在EST时区,因此返回的时间将根据你的tz进行调整:
t=# select '2017-12-21'::timestamptz;
timestamptz
------------------------
2017-12-21 00:00:00-05
(1 row)
区间匹配来自pg_timezone_names
和isequal -05
的utc_offset,因此它按预期工作。 (如果你set timezone to '-05'
,确实在EST将比UTC少5小时)相同的结果。
-05
和EST
都给出了SET TIMEZONE
的相同结果,如文档中所述。
现在,您使用interval
:https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-ZONECONVERT回答与文档的协调
在这些表达式中,期望的时区区域可以指定为文本字符串(例如,“PST”)或指定为间隔(例如,INTERVAL'-08:00')。
遵循这些规则也可以:
t=# select '2017-12-21'::timestamptz at time zone 'EST';
timezone
---------------------
2017-12-20 19:00:00
(1 row)
t=# select '2017-12-21'::timestamptz at time zone interval '-05:00';
timezone
---------------------
2017-12-20 19:00:00
(1 row)
但是,文档说:
在文本案例中,可以使用第8.5.3节中描述的任何方式指定时区名称。
这是https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-TIMEZONES
PostgreSQL允许您以三种不同的形式指定时区:
- 识别的时区名称列在pg_timezone_names中
- 公认的缩写列在pg_timezone_abbrevs中
- 形式为STDoffset或STDoffsetDST的POSIX风格时区规范
(格式化我的)
最后:
人们应该警惕POSIX风格的时区功能可以导致默默地接受虚假输入...另外要记住的一个问题是,在POSIX时区名称中,正偏移用于格林威治以西的位置。在其他地方,PostgreSQL遵循ISO-8601惯例,正面时区偏移位于格林威治以东。
所以简而言之 - 当你为timezone()
函数或AT TIME ZONE
指令定义'-05'作为文本(不是间隔)输入时(实际上相同)Postgres认为这是尝试使用POSIX样式时区并因此反转符号,因此你得到“对面“结果......
这个记录的反演的简单演示:
t=# select '2017-12-21'::timestamptz at time zone '05';
timezone
---------------------
2017-12-20 19:00:00
(1 row)
好吧,我想我找到了自己问题的答案:
根据PostgreSQL文档,第9.9.3节在以下链接https://www.postgresql.org/docs/9.6/static/functions-datetime.html
在这些表达式中,期望的时区区域可以指定为文本字符串(例如,“PST”)或指定为间隔(例如,INTERVAL'-08:00')。在文本案例中,可以使用第8.5.3节中描述的任何方式指定时区名称。
因此,使用INTERVAL
语法,以下似乎工作:
SELECT timezone(INTERVAL '-05:00', '2017-12-21');
timezone
---------------------
2017-12-20 19:00:00
我认为它仍然很奇怪,SELECT timezone('-05', '2017-12-21');
究竟意味着什么,因为以下内容也提供了预期的结果(添加了TZ偏移量):
SELECT timezone('-05', '2017-12-21'::timestamp);
timezone
------------------------
2017-12-20 19:00:00+00