为什么Postgres格式化timestamptz类型时间时会出现时区差异?
问题原因
pg(node-postgres)库存在默认行为:建立数据库连接时会自动将当前连接的会话时区设置为运行Node.js进程的操作系统时区,该配置优先级高于PostgreSQL服务端的全局时区设置。你本地PC和服务器的Node进程运行环境的系统时区不一致,导致两个环境的数据库会话时区不同。to_char处理timestamptz类型值时依赖当前数据库会话的时区:timestamptz底层存储的是UTC时间戳,转字符串格式时会基于会话时区做偏移计算。你本地会话时区为UTC+4,2021-11-02T19:00:00.000Z加4小时后对应日期为11月3日,因此返回dt: "03.11";服务器会话时区为UTC,直接用UTC时间转换得到的日期为11月2日,因此返回dt: "02.11"。- 两个环境返回的
begin_at字段值看起来一致,是因为pg库默认会将timestamptz类型转换为JavaScript原生Date对象,序列化输出时默认展示UTC格式的ISO字符串,因此不管会话时区是什么,该字段的序列化结果看起来完全相同,不代表时区处理逻辑一致。
修复方案
- 方案1:新建数据库连接后主动固定会话时区,每次建立连接/初始化连接池时执行语句:
SET TIME ZONE 'Asia/Yekaterinburg' - 方案2:写SQL时明确指定转换时区,完全规避会话时区的影响:
SELECT begin_at, to_char(begin_at AT TIME ZONE 'Asia/Yekaterinburg', 'DD.MM') AS dt FROM tasks WHERE begin_at >= $1 ORDER BY begin_at
内容的提问来源于stack exchange,提问作者Maxim Samburskiy
相关产品推荐
相关产品推荐

