You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Sequelize读取PostgreSQL UTC时区数据时的时间戳差异问题

问题描述

PostgreSQL配置文件postgresql.conf已将timezone设为UTC,且查询时执行了SET TIME ZONE 'UTC';和SET timezone TO 'UTC';命令,数据库中存储的时间戳如2023-08-25 08:37:02.000,通过Sequelize查询时,获取到的时间会比原时间晚8小时(变为2023-08-25 00:37:02.000)。

已尝试在Sequelize配置中添加dialectOptions和timezone参数,但未解决问题。需求是确保获取的时间戳与PostgreSQL配置一致,保持UTC时区。

特殊现象:使用findByPk能获取正确时间,但findAndCountAll查询时时间戳异常。


复现代码

SQL部分

create table test_time(
    alert_time timestamp
);

insert into test_time VALUES('2023-8-26 06:29:40');

select * from test_time;
-- 2023-08-26 06:29:40.000

show timezone; 
-- Asia/Taipei

SET TIME ZONE 'UTC';
SET timezone TO 'UTC'; 

show timezone; 
--UTC

Sequelize配置代码

const webConfig = require('../config/WebConfig');
const dbConfig = webConfig.dbConfig;
const debug = webConfig.debug;
const DataTypes = require('sequelize');
const {Op} = require('sequelize');
const initModels = require('./init-models');
const sequelize = new DataTypes(dbConfig.DB, dbConfig.USER, dbConfig.CODE, {
  host: dbConfig.HOST,
  port: dbConfig.PORT,
  dialect: dbConfig.dialect,
  logging: debug,
  dialectOptions: {useUTC:false},
});
//initModels are generated by sequelize-auto.
const db = initModels(sequelize);
db.op = Op;
db.sequelize = sequelize;
module.exports = db;

查询代码

const db = require('../models');
const TestTime = db.test_time;

exports.query = async (obj) => {
  try {
    const testTime = await TestTime.findAndCountAll(obj);
    return testTime;
  } catch (e) {
    console.log('\x1b[31m%s\x1b[0m', e);
  }
};

排查分析
  1. 时区配置冲突:当前Sequelize配置中dialectOptions.useUTC: false会强制驱动不使用UTC,而数据库已设为UTC,这会导致驱动将数据库返回的UTC时间转换为本地时区(如Asia/Taipei),后续处理又出现反转,最终产生时间差。
  2. sequelize-auto模型差异:findByPk与findAndCountAll的行为差异,大概率是sequelize-auto生成的模型中,timestamp字段的处理逻辑不一致——findByPk可能直接返回原始值,而findAndCountAll触发了模型的时区转换钩子。
  3. 连接级时区未同步:虽然执行了SET TIME ZONE 'UTC',但这是会话级配置,如果Sequelize创建新连接时未自动同步该配置,新连接的时区仍为默认的Asia/Taipei,导致查询时间转换异常。

解决方法

1. 修正Sequelize时区配置

修改Sequelize初始化配置,明确指定时区为UTC,调整驱动参数:

const sequelize = new DataTypes(dbConfig.DB, dbConfig.USER, dbConfig.CODE, {
  host: dbConfig.HOST,
  port: dbConfig.PORT,
  dialect: dbConfig.dialect,
  logging: debug,
  timezone: '+00:00', // 明确设置为UTC时区
  dialectOptions: {
    useUTC: true, // 驱动使用UTC处理时间
    dateStrings: true, // 强制返回字符串格式时间,避免自动转换
    typeCast: true
  },
});

2. 检查并修正sequelize-auto生成的模型

打开init-models生成的test_time.js模型文件,检查alert_time字段定义,确保类型为DataTypes.DATE且无额外时区转换配置。正确定义示例:

alert_time: {
  type: DataTypes.DATE,
  allowNull: true
}

若模型中存在defaultValue或get钩子进行时区转换,需移除这些逻辑,确保字段直接返回数据库存储的UTC时间。

3. 全局设置连接时区

在Sequelize初始化后,添加连接钩子,确保每个新连接自动设置时区为UTC:

// 钩子方式
sequelize.addHook('beforeConnect', (config) => {
  config.timezone = '+00:00';
});

// 或执行全局SQL语句
sequelize.query("SET TIME ZONE 'UTC';", { raw: true });

4. 验证并调整结果格式

修改配置后重新执行findAndCountAll查询,若返回的是字符串格式时间,可手动转换为带UTC标识的Date对象:

const result = await TestTime.findAndCountAll(obj);
result.rows.forEach(row => {
  row.alert_time = new Date(row.alert_time + 'Z'); // 添加Z标识UTC时间
});

内容的提问来源于stack exchange,提问作者huang7017

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 12:35:30