我有一些时间戳存储为Postgres类型timestamp without time zone
。
我将使用时间戳2013-12-20 20:45:27
作为示例。我打算这代表一个UTC时间戳。
在psql中,如果我运行查询SELECT start_time FROM table_name WHERE id = 1
,我会按预期返回该时间戳字符串:2013-12-20 20:45:27
。
但是,如果在我的Node应用程序中,我使用node-postgres库来运行相同的查询,我会在本地时区获取时间戳:Fri Dec 20 2013 20:45:27 GMT-0600 (CST)
。这是一个Javascript日期对象,但它已经存储为该时区。我真正想要的是一个代表2013-12-20 20:45:27 GMT+0000
的日期对象(甚至只是一个字符串)。我已经知道这次是UTC。
我已经尝试将postgresql.conf文件中的时区参数设置为:timezone = 'UTC'
,结果没有区别。
我做错了什么?
修改
问题似乎出现在此文件中:https://github.com/brianc/node-postgres/blob/master/lib/types/textParsers.js
如果从Postgres返回的日期字符串没有指定时区(即Z
或+06:30
,那么它只构建一个JavaScript日期对象,我相信它只包括本地时区。我需要更改我的应用程序以在DB中存储时区或覆盖此转换器。
答案 0 :(得分:16)
不是为了重振一个旧问题,而是看到我刚刚遇到完全相同的问题here,有一个替代解决方案可以通过覆盖用于timestamp without time zone
的类型解析器来实现:
var pg = require('pg');
var types = pg.types;
types.setTypeParser(1114, function(stringValue) {
return stringValue;
});
这将使node-pg不会将值解析为Date
对象,而是为您提供原始时间戳字符串。
来源:来自node-postgres issues
答案 1 :(得分:3)
这不是最好的解决方案,但我刚刚切换到使用Postgres类型timestamp with time zone
并确保我持久保存到数据库的所有日期都是UTC。
答案 2 :(得分:3)
您可以修改解析器,如@BadIdeaException所示。以下是有关它为什么没有按预期工作的更多细节,以及两种可能的解决方案。
对于类型为timestamp without time zone
的列,解析器会收到ISO 8601格式的字符串,但未指定时区:2016-07-12 22:47:34
每次在Javascript中创建Date对象时,如果未指定时区,则假定日期位于当前时区。对于UTC日期,根据定义属于GMT时区,这将为您提供不正确的绝对值(date.value)的日期,除非您的Javascript恰好在GMT时区中运行
因此, ISO 8601字符串不能由Date构造函数直接转换为UTC日期。您可以选择:修改字符串,使其解释为UTC:
var pg = require('pg');
var types = pg.types;
types.setTypeParser(1114, function(stringValue) {
return new Date(stringValue + "+0000");
});
或者使用"错误"创建日期。 (当前)时区,然后提取它的值(仍在当前时区),然后使用这些值在UTC时区生成日期。请注意,Date.UTC()返回日期值而不是对象,然后可以将其传递给Date构造函数。
types.setTypeParser(1114, function(stringValue) {
var temp = new Date(stringValue);
return new Date(Date.UTC(
temp.getFullYear(), temp.getMonth(), temp.getHours(), temp.getMinutes(), temp.getSeconds(), temp.getMilliseconds())
);
}
答案 3 :(得分:0)
我想知道@BadIdeaException是从哪里获得数字1114的。 在打字稿中,可以从界面看到值。
import { types } from 'pg';
types.setTypeParser(types.TypeId.TIME, (timeStr) => timeStr);
types.setTypeParser(types.TypeId.TIMESTAMP, (timeStr) => timeStr);
types.setTypeParser(types.TypeId.TIMESTAMPTZ, (timeStr) => timeStr);
这将覆盖所有时间戳字段解析器,并防止将字段错误地解析为Date对象。