PG承诺不返回"带时区的时间戳"字段正确

时间:2017-01-12 19:36:56

标签: javascript json postgresql pg-promise

我使用pg-promise lib与Postgres DB一起工作。我不明白为什么直接用

查询数据库
SELECT date FROM ro WHERE id = 13;

返回

date          
------------------------
 2017-01-19 00:00:00+02
(1 row)

和这个pgp电话:

var sql = 'SELECT date from ro WHERE id = 1366';
    Dbh.odb.any(sql)
      .then(ro => {
        console.log(ro);
        res.ok(ro)
      })

返回

{
    "date": "2017-01-18T22:00:00.000Z"
}

我期待的是

{
   "date": "2017-01-19T00:00:00.000Z"
}

2 个答案:

答案 0 :(得分:2)

您是否在运行pg-promise的同一台计算机上运行psql

来自timestamp with timezone

上的文档
  

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

     

当输出带有时区值的时间戳时,它始终从UTC转换为当前时区区域,并在该区域中显示为本地时间。要查看其他时区的时间,请更改时区或使用 AT TIME ZONE 构造(参见第9.9.3节)。

所以时区存储在UTC中,并根据TimeZone参数从该文档中检索(略微清理)

  

可以设置TimeZone配置参数,

     
      文件postgresql.conf中的
  1.   
  2. Chapter 19
  3. 中描述的任何其他标准方式   
  4. SQL命令SET TIME ZONE设置会话的时区。这是SET TIMEZONE TO的替代拼写,具有更多与SQL规范兼容的语法。
  5.   
  6. libpq客户端使用PGTZ环境变量在连接时向服务器发送SET TIME ZONE命令。
  7.   

所以你可以随时,

var sql = `SELECT date AT TIME ZONE '+02' from ro WHERE id = 1366`;
    Dbh.odb.any(sql)
      .then(ro => {
        console.log(ro);
        res.ok(ro)
      })

或者为客户端,会话或服务器设置时区。

您可以在此处找到timezone的潜在价值

SELECT * FROM pg_timezone_names();

答案 1 :(得分:2)

您的psql输出显示您的时间戳是午夜但是在UTC + 2时区(2017-01-19 00:00:00 + 02 ),这是两个小时在UTC之前。

也就是说,当UTC + 2的时间是00:00:00时,它只是UTC上一天的22:00:00 - 这就是你得到的:2017-01- 18T22 :00:00.000的ž

如果您从该UTC日期创建JavaScript日期,那么如果您使用的是UTC + 2,那么您将获得午夜。这是我在Chrome + 2上的Chrome控制台中看到的内容:

new Date('2017-01-18T22:00:00.000Z');
Thu Jan 19 2017 00:00:00 GMT+0200 (EET)

如果您真的希望将时间戳存储为午夜UTC,则应在插入日期时定义时区。但请注意,它不会是UTC + 2的午夜:

new Date('2017-01-19T00:00:00.000Z');
Thu Jan 19 2017 02:00:00 GMT+0200 (EET)