【问题标题】:How to prevent Sequelize from converting Date object to local time如何防止 Sequelize 将 Date 对象转换为本地时间
【发布时间】:2018-11-05 21:12:18
【问题描述】:

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

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

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

这里是一些示例代码。如果你想自己运行它,我还创建了一个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;
}

【问题讨论】:

    标签: node.js sequelize.js utc


    【解决方案1】:

    问题是日期被创建为 UTC 时间,但因为 DATEONLY 不知道时区,它以 YYYY-MM-DD 格式“按原样”(本地时间)格式化 Date 对象(使用 moment. js - see here in source)。

    对于DATEONLY,您可以这样做:

    var date = new Date(2000, 9, 31);
    

    这将正确插入日期。

    程序员很少这么说,但有一次你对时区的考虑太多了!


    旧答案不正确

    这取决于您检查该值的方式,但 javascript 和 postgresql 会将其转换为您的本地时区以进行显示。

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

    postgresql docs 中写道:

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

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

    如果您在 postgresql 中输出时间值,请尝试将其转换为 UTC。如果您使用 javascript 输出它,请尝试 date.toUTCString()

    您的 hack 似乎有效的原因是因为它们实际上存储了 2000-11-01 05:00,但是当您检查该值时,它会转换为您的本地时区。

    【讨论】:

    • Sequelize 没有将日期字段创建为 TIMESTAMP WITH TIMEZONE 类型,因为我没有使用 Sequelize.DATE 类型。我正在使用Sequelize.DATEONLY,它创建了一个postgres DATE 字段,它没有时间数据。
    • 如何检查表的值?在 postgresql 或 javascript 中?
    • 我在 postgres 中查看它们
    • 如果您运行SELECT your_date_field AT TIME ZONE 'GMT' FROM your_table,它会显示正确的日期吗?抱歉,我手边没有 postgresql 安装...
    • 它显示2018-10-31 05:00:00这是正确的日期,但是由于postgres不在DATE字段中存储时间值,时间有意义吗?看起来它假设我的时间是午夜(UTC-5),然后通过增加 5 小时将其转换为 UTC。
    猜你喜欢
    • 2021-07-02
    • 1970-01-01
    • 2011-04-14
    • 1970-01-01
    • 2015-12-19
    • 2016-11-27
    相关资源
    最近更新 更多