为什么在使用 UCT 值与时区名称时在 postgresql 中得到不同的值?

Why do I get different values in postgresql when using UCT values vs timezone names?

如果我运行这个查询:

SELECT ('2021-11-02 08:00:00+00' AT TIME ZONE 'UCT') at TIME ZONE 'UCT+2';

它给出了这个结果:

2021-11-02 10:00:00+00

这对我来说似乎是正确的...

但是,我的时区数据采用字符串格式,例如:“Africa/Johannesburg”,我知道它在 UCT+2 时区。

但是运行宁此查询:

SELECT ('2021-11-02 08:00:00+00' AT TIME ZONE 'UCT') at TIME ZONE 'Africa/Johannesburg';

给出这个结果:

2021-11-02 06:00:00+00

这与我预期的相反。我知道我可以编写代码将字符串转换为 UCT 值,但我不明白为什么字符串值似乎与使用 UCT 值相反。有人可以解释为什么会这样吗?

哇,这里有很多东西要打开。

最主要的是(对 mis-quote Inigo Montoya)我不认为 UTC+2 是你认为的那样。

这里的一件重要事情是精确的格式。

你说你得到这个结果:

2021-11-02 06:00:00+00

但我得到的是:

2021-11-02 06:00:00

这真的很重要,因为我得到的不包括 +00。那是因为它仍然是 08:00+00 时区。

AT TIME ZONE 语法表示“这个地方的本地人在这个特定的 UTC 时间会看到什么时间?”。约翰内斯堡的某个人会将其视为 10:00。伦敦(冬天)的人会将其视为 06:00。但这是同一时刻。

因此 AT TIME ZONE 的输出通常不包含与 UTC (+00) 的时区偏移量。

您使用两个 AT TIME ZONE 子句进行的转换是多余的。因为它 知道 它在那个时区,因此 UCT 时间是多少。你会用一个 AT TIME ZONE 子句得到相同的结果(试一试)。

您得到不同答案的原因似乎是因为 PostgreSQL 不会将 UCT+2 解释为比 UCT 早 2 小时的时区。它解释为您指定 POSIX 时区定义,其中还可以包括夏令时规则等。

此页面:https://www.postgresql.org/docs/current/datatype-datetime.html 表示 PostgreSQL 将接受以 3 种方式指定的时区:

  • 全名 - 例如'Africa/Johannesburg'
  • 缩写 - 例如'SAST'
  • Posix 格式,例如'CET-1CEST,M3.5.0,M10.5.0/3'(这显然是巴黎)

实际上,它不包括 Posix 格式示例,它位于此页面上:https://www.postgresql.org/docs/current/datetime-posix-timezone-specs.html

基本上,posix 格式是一种指定时区规则的方式。

类似

[abbreviation][offset][daylight savings abbrev][DST offset][dst rules]

所以说 'UCT+2' 可能是“错误的形式”,因为您试图更改具有标准用法的缩写词 'UTC' 的含义。

您可以确认它没有使用您所在时区的“UCT”部分来引用实际 UCT 时区。如果你这样做:

SELECT ('2021-11-02 08:00:00+00' AT TIME ZONE 'BOB')

PostgreSQL 会说它无法识别时区“BOB”。

但如果你这样做

SELECT ('2021-11-02 08:00:00+00' AT TIME ZONE 'BOB+2')

它会很乐意给你06:00:00。事实上,如果你愿意,你可以把(几乎)任何东西粘在那里而不是“UCT”。它不会用于计算。

请注意,我链接的 posix 页面显示

POSIX time zone specifications are inadequate to deal with the complexity of real-world time zone history, but there are sometimes reasons to use them.

最后,'UCT' 是完全有效的,但它让我头疼。我只看到它是 'UTC',所以直到。