如何防止Sequelize将Date对象转换为本地时间

时间:2018-05-26 20:14:17

标签: node.js sequelize.js utc

我正在使用sequelize作为节点项目。它连接到Postgres数据库,其中包含一个带有DATE字段的表(与TIMESTAMP WITH TIMEZONE不同,DATE没有时间数据)。

在代码中我使用javascript Date对象建模日期,该对象将时间存储为UTC午夜。当我使用它来使用Date对象将记录插入表中时,sequelize显然首先将其转换为本地时间,因为记录总是落后1天。所以,如果我想将2000-10-31插入数据库,我最终会得到2000-10-30。我在UTC-5。

在插入数据库之前,如何告诉sequelize不将Date转换为本地时间?

以下是一些示例代码。如果你想自己运行它,我还创建了一个repository

var Sequelize = require('sequelize');

const sequelize = new Sequelize('testdb', 'postgres', '???', {
    host: 'localhost',
    dialect: 'postgres'
});

TestTable = sequelize.define('date_test',
    {
        id: {
            primaryKey: true,
            type: Sequelize.INTEGER,
            autoIncrement: true
        },

        someDate: {
            field: 'some_date',
            type: Sequelize.DATEONLY
        }
    },
    {
        timestamps: false,
        freezeTableName: true
    }
);

// midnight UTC on Halloween 
var date = new Date(Date.UTC(2000, 9, 31));

// converts to local time resulting in 2000-10-30
TestTable.create({ someDate: date })
    .then(function() {
        // also apparently converts to local time resulting in 2000-10-30
        return TestTable.create({ someDate: date.toUTCString() });
    })
    .then(function() {
        // convert to string, definitely works but seems unnecessary
        var strDate = date.getUTCFullYear() + '-' + pad2(date.getUTCMonth() + 1) + '-' + pad2(date.getUTCDate());
        return TestTable.create({ someDate: strDate });
    })
    .then(function() {
        // cerate a new local Date, also works but seems hacky
        var newDate = new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
        return TestTable.create({ someDate: newDate });
    })
    .then(function() {
        process.exit(0);
    });


function pad2(n) {
    if (n.length === 1) {
        return '0' + n;
    }

    return n;
}

1 个答案:

答案 0 :(得分:1)

问题是日期是作为UTC时间创建的,但由于YYYY-MM-DD没有时区意识,因此它格式化DATEONLY格式化Date对象“按原样”(在本地时间) (使用moment.js - Show a => a -> String)。

对于var date = new Date(2000, 9, 31); ,你可以这样做:

date.toUTCString()

这将正确插入日期。

程序员很少这么说,但是一旦你想到关于时区的太多了!

旧的不正确答案

这取决于您如何检查该值,但javascript和postgresql正在将其转换为您当地的时区以供显示。

Sequelize使用 TIMESTAMP WITH TIMEZONE 类型作为日期字段(see here in source)。

source中说:

  

对于带时区的时间戳,内部存储的值始终为UTC(通用协调时间,传统上称为格林威治标准时间,GMT)。具有指定显式时区的输入值将使用该时区的适当偏移量转换为UTC。如果输入字符串中未指定时区,则假定它位于系统时区参数指示的时区中,并使用时区区域的偏移量转换为UTC。

     

当输出带有时区值的时间戳时,它始终从UTC转换为当前时区区域,并在该区域中显示为本地时间。要查看另一个时区的时间,请更改时区或使用AT TIME ZONE构造(参见第9.9.3节)。

如果要在postgresql中输出时间值,请尝试将其转换为UTC。如果您要在javascript中输出,请尝试2000-11-01 05:00

你的hack看起来有效的原因是因为它们实际上存储了zipfiles that span multiple disks are not supported 但是当你检查这个值时,它会转换成你当地的时区。