PostgreSQL 17: 使用 AT LOCAL 指定本地时区

John Doe 六月 3, 2025

你的应用软件需要支持多时区吗?或者,你需要在多个时区之间转换时间吗?

与 SQL 共舞的大象

特性提交日志

添加对 AT LOCAL 的支持。

当在带时区或不带时区的时间戳之间进行转换时,SQL 标准规定了 AT TIME ZONE 的 AT LOCAL 变体,该变体使用会话的时区。这包括三个系统函数,它们能够以一种与现有的 AT TIME ZONE 形式相同的方式执行转换工作,但需要将这些函数标记为 stable(稳定),因为它们依赖于会话的 timezone 参数设置。

讨论:https://postgr.es/m/8e25dec4-5667-c1a5-6581-167d710c2182@postgresfriends.org

示例

本次提交的特性,让 PostgreSQL 可以支持使用 “AT LOCAL” 语法转换为本地会话的时区。

让我们看看如何进行时区转换。以下是一个非常简单的示例:

postgres=# show timezone;
   TimeZone
---------------
 Asia/Shanghai
(1 row)

postgres=# select now();
              now
-------------------------------
 2025-05-02 21:43:28.395172+08
(1 row)

postgres=# select now() at time zone 'UTC';
         timezone
---------------------------
 2025-05-02 13:43:36.80314
(1 row)

postgres=# select now() at time zone 'UTC-8';
          timezone
----------------------------
 2025-05-02 21:44:11.295156
(1 row)

这将返回当前时间,以 “UTC” 和 “UTC-8”(服务器当前的时区)表示。更易读的格式是使用时区名称,例如:

postgres=# select now() at time zone 'Asia/Shanghai';
          timezone
----------------------------
 2025-05-02 21:44:40.680735
(1 row)

所有可用的时区名称都列在系统视图 pg_timezone_names 中:

postgres=# select * from pg_timezone_names limit 10;
        name         | abbrev | utc_offset | is_dst
---------------------+--------+------------+--------
 Arctic/Longyearbyen | CEST   | 02:00:00   | t
 Eire                | IST    | 01:00:00   | f
 Egypt               | EEST   | 03:00:00   | t
 CST6CDT             | CDT    | -05:00:00  | t
 MST7MDT             | MDT    | -06:00:00  | t
 Africa/Johannesburg | SAST   | 02:00:00   | f
 Africa/El_Aaiun     | +01    | 01:00:00   | f
 Africa/Banjul       | GMT    | 00:00:00   | f
 Africa/Blantyre     | CAT    | 02:00:00   | f
 Africa/Maputo       | CAT    | 02:00:00   | f
(10 rows)

如果您想知道 “Africa/Maputo” 的当前时间,这很简单:

postgres=# select now() at time zone 'Africa/Maputo';
          timezone
----------------------------
 2025-05-02 15:45:43.737949
(1 row)

使用新版本的 PostgreSQL,您还可以使用 “AT LOCAL” 语法:

postgres=# set timezone to 'Egypt';
SET
postgres=# select now() at local;
          timezone
----------------------------
 2025-05-02 16:46:29.448678
(1 row)

postgres=# select now() at local timezone;
         timezone
---------------------------
 2025-05-02 16:46:38.07518
(1 row)

postgres=# set timezone to 'Africa/Blantyre';
SET
postgres=# select now() at local;
          timezone
----------------------------
 2025-05-02 15:47:07.106363
(1 row)

postgres=# select now() at local timezone;
          timezone
----------------------------
 2025-05-02 15:47:13.321566
(1 row)

语法中的关键字 “timezone” 是可选的,可以省略。

非常不错的体验,感谢所有参与的社区人员。

参考

提交日志:https://git.postgresql.org/pg/commitdiff/97957fdbaa429c7c582d4753b108cb1e23e1b28a