关于node.js:使用node-postgres在utc中获取Postgres“没有时区的时间戳”

Use node-postgres to get Postgres “timestamp without timezone” in utc

我有一些时间戳记存储为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日期对象,我相信它将包括本地时区。更改我的应用以在数据库中存储时区或覆盖此转换器。


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

1
2
3
4
5
var pg = require('pg');
var types = pg.types;
types.setTypeParser(1114, FUNCTION(stringValue) {
RETURN stringValue;
});

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

来源:从node-postgres问题获得


您可以按照@BadIdeaException的建议修改解析器。以下是有关为何无法按预期运行的更多详细信息,以及两种可能的解决方案。

对于类型为timestamp without time zone的列,解析器将接收ISO 8601格式的字符串,且未指定时区:2016-07-12 22:47:34

任何时候在Javascript中创建Date对象时,如果未指定时区,则会假定该日期在当前时区中。对于UTC日期,根据定义,该日期位于GMT时区,除非您的Javascript恰好在GMT时区中运行,否则它将为您提供一个具有不正确的绝对值(date.value)的日期。

因此,该ISO 8601字符串不能通过Date构造函数直接转换为UTC日期。您的选择是:修改字符串,以便将其解释为UTC:

1
2
3
4
5
var pg = require('pg');
var types = pg.types;
types.setTypeParser(1114, FUNCTION(stringValue) {
    RETURN NEW DATE(stringValue +"+0000");
});

或使用"错误的"(当前)时区创建日期,然后为其提取值(仍在当前时区中),然后使用这些值在UTC时区中生成日期。请注意,Date.UTC()返回一个日期值而不是一个对象,然后可以将其传递给Date构造函数。

1
2
3
4
5
6
7
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())
    );
}


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