我正在使用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;
}
答案 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
但是当你检查这个值时,它会转换成你当地的时区。