如何配置pg库将PostgreSQL无时区时间戳读取为UTC时间戳
问题描述
- 本地时区:UTC/GMT +3小时
- 数据库表结构(PostgreSQL):
CREATE TABLE public.order_invoices ( created_at timestamp NOT NULL, updated_at timestamp NOT NULL, order_id uuid NOT NULL, document_id varchar(100) NULL, status varchar(20) NOT NULL, CONSTRAINT order_invoices_pkey PRIMARY KEY (order_id) );
- 写入数据的代码:
markInvoiceWaitingForApf(order: Order): Promise<void> { return this.sql.executeInTransaction(async tx => { await tx.executeStatement( `INSERT INTO order_invoices(order_id, status, created_at, updated_at) VALUES ($1, $2, $3, CURRENT_TIMESTAMP) ON CONFLICT (order_id) DO UPDATE SET updated_at = CURRENT_TIMESTAMP, status = $2 WHERE order_invoices.status = 'WAITING_FOR_APF'`, [order.id, OrderInvoiceStatus.WAITING_FOR_APF, parseISO(order.orderDate).toISOString()]) }) }
底层通过pg.ClientBase.query(sql, params)执行,客户端由const client = await pg.Pool.connect()创建。
- 现象:写入时的时间为
"2024-07-09T12:32:30.214Z",读取后得到"2024-07-09T09:32:30.227Z",pg库默认将PostgreSQL的无时区时间戳解析为本地时间戳,导致时区偏移。
解决方案
pg库允许通过自定义类型解析器修改无时区时间戳(timestamp类型,OID为1114)的解析行为,以下两种方式可解决问题:
方式1:解析为UTC时间戳
修改类型解析器,将数据库返回的时间字符串当作UTC时间处理,生成的Date对象调用toISOString()会得到正确的UTC时间:
const { types } = require('pg'); // 配置PostgreSQL timestamp类型(无时区)的解析器 types.setTypeParser(1114, (value) => { // 在原始时间字符串后添加Z,标记为UTC时间 return new Date(`${value}Z`); });
方式2:读取为原始字符串(Naive时间戳)
如果不需要转换为Date对象,直接获取数据库中存储的原始时间字符串:
const { types } = require('pg'); types.setTypeParser(1114, (value) => { // 直接返回数据库中的原始时间字符串,如'2024-07-09 12:32:30.214' return value; });
补充说明
写入时使用toISOString()生成的是UTC时间字符串,PostgreSQL的timestamp字段会丢弃时区信息,仅保留时间部分。默认解析逻辑会将该时间视为本地时间(UTC+3),转换为UTC时自动减去3小时,导致结果偏移。通过上述配置可覆盖默认解析行为,得到预期的时间值。
内容的提问来源于stack exchange,提问作者korulis
相关产品推荐
相关产品推荐

