Sequelize连接PostgreSQL时区不生效,读取日期始终为UTC如何解决?
问题
向PostgreSQL插入的数据如下:
{ "word": "test", "wordLanguage": "eng", "testDate": "2024-07-08T15:00:00+03:00" }
读取后得到的数据为:
{ "id": 8, "word": "test", "wordLanguage": "eng", "testDate": "2024-07-08T12:00:00.000Z", "updatedAt": "2024-07-08T15:20:17.906Z", "createdAt": "2024-07-08T15:20:17.906Z" }
期望testDate保持GMT+3时区的15:00,而非UTC的12:00。
相关配置信息:
- Word模型定义:
sequelize.define('Word', { word: { type: DataTypes.STRING, allowNull: false, }, wordLanguage: { type: DataTypes.ENUM, allowNull: false, values: ['eng', 'tr'], }, testDate: { type: DataTypes.DATE, allowNull: false, }, })
- Sequelize连接配置:
const sequelize = new Sequelize('db123', 'user123', 'password123', { host: 'db', port: 5432, dialect: 'postgres', timezone: 'Europe/Istanbul', dialectOptions: { useUTC: false, }, logging: true, });
- 数据库与系统时区:
- DBeaver执行
show timezone结果为GMT+3 - 系统日期输出:
# date Mon Jul 8 06:25:18 PM +03 2024
所有配置均为GMT+3,为何读取结果仍为UTC?该如何修复?
解决方案
问题根源
- PostgreSQL的
TIMESTAMP WITH TIME ZONE(对应Sequelize的DATE类型)会将所有输入时间转换为UTC存储,读取时默认返回UTC时间。 - Sequelize默认会把
DATE类型数据序列化为UTC格式的Date对象字符串(带Z后缀),即使配置了全局时区,默认序列化逻辑不会自动转换为目标时区。 dialectOptions.useUTC在PostgreSQL环境下仅影响写入时的时区转换,无法直接控制读取后的输出格式。
修复方案
方案1:全局配置时区与日期序列化
修改Sequelize连接配置,强制返回目标时区的字符串格式,而非自动转换为UTC的Date对象:
const sequelize = new Sequelize('db123', 'user123', 'password123', { host: 'db', port: 5432, dialect: 'postgres', timezone: 'Europe/Istanbul', dialectOptions: { useUTC: false, dateStrings: true, // 让PostgreSQL返回字符串格式日期 typeCast: true, // 确保类型转换正确 }, logging: true, });
方案2:模型字段级钩子转换
针对testDate字段添加读取钩子,手动将UTC时间转换为目标时区的指定格式:
sequelize.define('Word', { word: { type: DataTypes.STRING, allowNull: false, }, wordLanguage: { type: DataTypes.ENUM, allowNull: false, values: ['eng', 'tr'], }, testDate: { type: DataTypes.DATE, allowNull: false, get() { const rawValue = this.getDataValue('testDate'); if (rawValue instanceof Date) { // 转换为Europe/Istanbul时区的ISO格式字符串 return rawValue.toLocaleString('en-US', { timeZone: 'Europe/Istanbul', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$3-$2-$1').replace(/, /, 'T'); } return rawValue; } }, })
方案3:查询时显式转换时区
使用PostgreSQL的AT TIME ZONE函数在查询阶段直接转换时区并格式化:
const words = await Word.findAll({ attributes: [ 'id', 'word', 'wordLanguage', // 将UTC时间转换为Europe/Istanbul时区并格式化 [sequelize.fn('to_char', sequelize.fn('AT TIME ZONE', sequelize.col('testDate'), 'Europe/Istanbul'), 'YYYY-MM-DD"T"HH24:MI:SS'), 'testDate'], 'updatedAt', 'createdAt' ] });
内容的提问来源于stack exchange,提问作者Tolgay Toklar
相关产品推荐
相关产品推荐

