22

我有一些时间戳存储为 Postgres 类型timestamp without time zone

我将以时间戳2013-12-20 20:45:27为例。我打算这代表一个UTC时间戳。

在 psql 中,如果我运行 query 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 日期对象,我相信它只会包含本地时区。我要么需要更改我的应用程序以存储数据库中的时区或覆盖此转换器。

4

4 回答 4

23

不是要重提一个老问题,而是看看我在这里遇到了完全相同的问题,有一个替代解决方案可以通过覆盖用于的类型解析器来工作timestamp without time zone

var pg = require('pg');
var types = pg.types;
types.setTypeParser(1114, function(stringValue) {
return stringValue;
});

这将使 node-pg 无法将值解析为Date对象,而是为您提供原始时间戳字符串。

资料来源:从node-postgres 问题中得到它

于 2014-04-06T10:32:01.190 回答
10

正如@BadIdeaException 建议的那样,您可以修改解析器。以下是有关为什么它无法按预期工作的更多详细信息,以及两种可能的解决方案。

对于 type 的列timestamp without time zone,解析器接收一个 ISO 8601 格式的字符串,没有指定时区:2016-07-12 22:47:34

每当您在 Javascript 中创建 Date 对象时,如果您未指定时区,则假定日期在当前时区中。对于定义为 GMT 时区的 UTC 日期,这将为您提供一个绝对值不正确的日期 (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.getDate(), temp.getHours(), temp.getMinutes(), temp.getSeconds(), temp.getMilliseconds())
    );
}
于 2016-07-12T23:29:51.027 回答
5

这不是最好的解决方案,但我只是切换到使用 Postgres 类型timestamp with time zone并确保我坚持到数据库的所有日期都是 UTC。

于 2013-12-20T23:32:41.257 回答
1

我想知道@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 对象。

于 2020-11-11T10:09:25.607 回答