PostgreSQL 1991 年时间自动变成 +09:00

问题

开发时发现一个 1991 年出生用户的时间数据出现异常:

  • 数据库:PostgreSQL
  • 字段:TIMESTAMP
  • 时区:Asia/Shanghai
  • 预期:UTC+08:00
  • 实际:始终被解析成 UTC+09:00

一开始怀疑是 PostgreSQL、ORM 或程序时区配置错误,但实际原因是历史夏令时。

原因

Asia/Shanghai 并不代表“永远固定 UTC+8”。

它是 IANA 地区时区,会根据具体日期查询当时实际使用的时区规则。

中国曾在以下年份实行夏令时:

  • 1986
  • 1987
  • 1988
  • 1989
  • 1990
  • 1991

夏令时期间,中国标准时间会从:

UTC+08:00

变为:

UTC+09:00

因此,如果一个 1991 年的日期刚好落在当年的夏令时期间:

1991 日期 + Asia/Shanghai

就会正确地被解析成:

UTC+09:00

这不是 PostgreSQL 的 Bug,而是历史时区规则导致的正常结果。

避坑

不要把:

Asia/Shanghai

理解成:

固定 UTC+08:00

两者含义不同:

  • Asia/Shanghai:地区时区,会应用历史夏令时规则
  • +08:00:固定 UTC Offset,不考虑历史规则

另外,生日本质上只是“日期”,通常不应该使用 TIMESTAMP

推荐:

PostgreSQL DATE

而不是:

TIMESTAMP / TIMESTAMPTZ

一句话总结:

地区时区是历史规则,不是固定偏移;生日是日期,不是时间点。