PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

B.5. POSIX 时区规范 #

PostgreSQL 可以接受按照 POSIX 标准关于 TZ 环境变量的规则书写的时区规范。 POSIX 时区规范不足以应对真实世界时区历史的 复杂性,但有时会有使用它们的理由。

POSIX 时区规范的形式是

STD offset [ DST [ dstoffset ] [ , rule ] ]

(为了可读性,我们在字段之间显示了空格,但实践中不应使用空格。) 这些字段是:

在这个语法中,时区缩写可以是一个字母串,例如 EST,或者由尖括号包围的任意字符串,例如 <UTC-05>。 注意,这里给出的时区缩写只用于输出,而且即便如此也只在某些时间戳 输出格式中使用。时间戳输入中可识别的时区缩写按 Section B.4 中解释的方式决定。

偏移字段指定与 UTC 相差的小时数,可选地还有分钟数和秒数。 它们的格式是 hh[:mm[:ss]], 可选地带有前导符号(+ 或 -)。 正号用于格林尼治 以西的时区。 (注意,这与 PostgreSQL 其他地方使用的 ISO-8601 符号 约定相反。) hh 可以是一位或两位数字;mm 和 ss(如果使用)必须是两位。

夏令时转换 rule 的 格式是

dstdate [ / dsttime ] , stddate [ / stdtime ]

(与前文一样,实践中不应包含空格。) dstdate 和 dsttime 字段定义夏令时何时开始, 而 stddate 和 stdtime 定义标准时间何时开始。 (在某些情况下,特别是赤道以南的时区,前者在一年中可能比后者更 晚。)日期字段具有以下格式之一:

n

一个普通整数表示一年中的一天,从零计数到 364,闰年则为 365。

Jn

在这种形式中,n 从 1 计数到 365, 即使存在 2 月 29 日也不计入它。 (因此,发生在 2 月 29 日的转换无法用这种方式指定。 不过,2 月之后的日子的编号在闰年和非闰年是相同的,因此对于 固定日期的转换,这种形式通常比普通整数形式更有用。)

Mm.n.d

这种形式指定一个总是发生在同一个月的同一个星期的转换。 m 标识月份,从 1 到 12。 n 指定由 d 标识的星期几的第 n 次出现。 n 是 1 到 4 之间的数字,或者 5 表示 该星期几在本月中的最后一次出现(可能是第四次或第五次)。 d 是 0 到 6 之间的数字,0 表示星期日。 例如,M3.2.0 表示 “三月的第二个星期日”。

Note

M 格式足以描述许多常见的夏令时转换法规。 但请注意,这些变体都无法应对夏令时法规的变化,因此在实践中, 为命名时区存储的历史数据(存放在 IANA 时区数据库中)对于正确解释 过去的时间戳是必要的。

转换规则中的时间字段具有与之前描述的偏移字段相同的格式,只是它们 不能包含符号。 它们定义发生向另一种时间转换时的当前本地时间。 如果省略,它们默认为 02:00:00。

如果给出了夏令时缩写但省略了转换 rule 字段, 回退行为是使用规则 M3.2.0,M11.1.0,它对应于 2020 年的美国做法(即在三月第二个星期日拨快,在十一月第一个星期日 拨回,两次转换都发生在当地通行时间的凌晨 2 点)。 注意,这条规则对 2007 年之前的年份不能给出正确的美国转换 日期。

举个例子,CET-1CEST,M3.5.0,M10.5.0/3 描述了巴黎 当前(截至 2020 年)的计时做法。 这个规范说标准时间的缩写是 CET,比 UTC 早 (东)一个小时;夏令时的 缩写 CEST,隐式地比 UTC 早两个小时; 夏令时从三月的最后一个星期日 CET 凌晨 2 点开始,到十月的最后一个 星期日 CEST 凌晨 3 点结束。

四个时区名 EST5EDT、 CST6CDT、MST7MDT 和 PST8PDT 看起来像是 POSIX 时区 规范。然而,它们实际上被当作命名时区处理, 因为(出于历史原因)IANA 时区数据库中存在以这些名字命名的文件。 这样做的实际影响是:这些时区名会产生有效的美国历史夏令时 转换,而单纯的 POSIX 规范则不会。

需要警惕的是,POSIX 风格的时区规范很容易写错,因为对时区缩写的 合理性没有任何检查。 例如,SET TIMEZONE TO FOOBAR0 是可行的,会让系统有效地使用一个相当古怪的 UTC 缩写。