postgresql 时区转换 'EST' != '-05'

postgresql timezone conversion 'EST' != '-05'

我在 x86_64-pc-linux-gnu 运行 PostgreSQL 9.6.6,我的时区设置为 'UTC'.

有谁知道为什么以下SELECT语句的结果不同?

A)

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 table -05 应该与 EST 具有相同的偏移量...有什么想法吗?谢谢。

好的,我想我找到了自己问题的答案:

根据 PostgreSQL 文档,第 9.9.3 节位于以下 link https://www.postgresql.org/docs/9.6/static/functions-datetime.html

In these expressions, the desired time zone zone can be specified either as a text string (e.g., 'PST') or as an interval (e.g., INTERVAL '-08:00'). In the text case, a time zone name can be specified in any of the ways described in Section 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

https://www.postgresql.org/docs/current/static/view-pg-timezone-names.html

The view pg_timezone_names provides a list of time zone names that are recognized by SET TIMEZONE

还有:

utc_offset interval Offset from UTC (positive means east of Greenwich)

当您 set timezone to 'EST' - 您声明您的客户处于 EST 时区,因此返回的时间将根据您的时间进行调整:

t=# select '2017-12-21'::timestamptz;
      timestamptz
------------------------
 2017-12-21 00:00:00-05
(1 row)

间隔与 pg_timezone_names 的 utc_offset 相匹配并且等于 -05,因此它按预期工作。 (实际上,在 EST 中将比 UTC 少 5 小时)如果您 set timezone to '-05',结果相同。

-05EST 都为 SET TIMEZONE 给出相同的结果,如文档中所述。

现在你回答与文档协调使用intervalhttps://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-ZONECONVERT

In these expressions, the desired time zone zone can be specified either as a text string (e.g., 'PST') or as an interval (e.g., 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)

但进一步,文档说:

In the text case, a time zone name can be specified in any of the ways described in Section 8.5.3.

https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-TIMEZONES

PostgreSQL allows you to specify time zones in three different forms:

  • recognized time zone names are listed in the pg_timezone_names
  • recognized abbreviations are listed in the pg_timezone_abbrevs
  • POSIX-style time zone specifications of the form STDoffset or STDoffsetDST

(格式化我的)

最后:

One should be wary that the POSIX-style time zone feature can lead to silently accepting bogus input...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.

TL;DR

所以简而言之 - 当您将'-05'定义为timezone()函数或AT TIME ZONE指令的文本(不是间隔)输入时(实际上相同) Postgres 认为这是尝试使用 POSIX 样式时区 并因此反转符号 ,因此你得到 "opposite" 结果...

这个记录的反转的简单演示:

t=# select '2017-12-21'::timestamptz at time zone '05';
      timezone
---------------------
 2017-12-20 19:00:00
(1 row)