javascript + postgres:时区和时间戳的使用

Posted

技术标签:

【中文标题】javascript + postgres:时区和时间戳的使用【英文标题】:javascript + postgres: timezone and timestamp usage 【发布时间】:2015-11-09 01:41:29 【问题描述】:

我不太了解时间戳的用法, 例如 用户创建文章,可以选择PublishDate,系统也会自动存储CreateDate

一个。我应该使用时区制作PublishDateCreateDate 时间戳并设置UTC?

b.用户发布字符串,然后我像下面使用momentjs 转换为utc 时间戳并存储,当有人选择此行时,将它们显示为用户客户端时间反向使用momentjs

c。我使用CURRENT_TIMESTAMPCreateDateCURRENT_TIMESTAMP 这是否意味着服务器时间?我做对了吗?

我的想法是我总是将 utc 时区时间戳插入数据库,并且无论用户/客户端读取的位置,将数据转换为用户/客户端时区?我做对了吗?

一个。我的数据库(postgres)由

创建
CREATE TABLE IF NOT EXISTS "Article"(
"ArticleId" SERIAL NOT NULL,
"PublishDate" timestamp with time zone,
"Active" bit NOT NULL,
"CreateByUserId" integer,
"CreateDate" timestamp with time zone,
PRIMARY KEY ("ArticleId")
);

SET timezone = 'UTC';

b.用户提交帖子到存储(nodejs)

// publishDate: '"y":2015,"m":8,"d":16,"h":15,"mi":46,"s":24
var publishDate = JSON.parse(req.body.publishDate); 

var leadingZeroAndDateFormat = function(publishDate) 
  return new Promise(function (fulfill, reject)
    if (publishDate.m < 10)  publishDate.m = '0'+publishDate.m; 
    if (publishDate.d < 10)  publishDate.d = '0'+publishDate.d; 
    if (publishDate.h < 10)  publishDate.h = '0'+publishDate.h; 
    if (publishDate.mi < 10)  publishDate.mi = '0'+publishDate.mi; 
    if (publishDate.s < 10)  publishDate.s = '0'+publishDate.s; 
    var str = publishDate.y+'-'+publishDate.m+'-'+publishDate.d+' '+publishDate.h+':'+publishDate.mi+':'+publishDate.s;
    var utc = moment(str).unix();
    fulfill(utc);
  );
;

c。将CreateDate 插入数据库使用CURRENT_TIMESTAMP

var insertArticle = function(publishDate, active, createByUserId) 
return new Promise(function (fulfill, reject)
  var query = 'INSERT INTO "Article" ("PublishDate","Active","CreateByUserId","CreateDate") VALUES ($1,$2,$3,CURRENT_TIMESTAMP) RETURNING "ArticleId"';
  dbClient.query(query,[publishDate,active,createByUserId], function(error, result) 
    if (error) 
      reject(error);
     else 
      fulfill(result);
    
  );
);
;

更新 当我更改没有时区的所有列时,我执行insertArticle 显示错误

[error: date/time field value out of range: "1439717298"] name: 'error', length: 158, severity: 'ERROR', code: '22008', detail: undefined, hint: 'Perhaps you need a different "datestyle" setting.', position: undefined, internalPosition: undefined, internalQuery: undefined, where: undefined, schema: undefined, table: undefined, column: undefined, dataType: undefined, constraint: undefined, file: 'datetime.c', line: '3775', routine: 'DateTimeParseError'

var insertArticle = function(publishDate, active, createByUserId) 
return new Promise(function (fulfill, reject)
  var query = 'INSERT INTO "Article" ("PublishDate","Active","CreateByUserId","CreateDate") VALUES ($1,$2,$3,$4) RETURNING "ArticleId"';
  dbClient.query(query,[publishDate,active,createByUserId,moment.utc().unix()], function(error, result) 
    if (error) 
      reject(error);
     else 
       fulfill(result);
    
  );
);
;

【问题讨论】:

始终使用 UTC 时间和没有时区的时间戳,因为不需要存储不同的时区。如果需要,然后在表示层处理区域。 感谢您的回复,是否意味着将列设置为不带时区?然后在插入时使用 momentjs utc 时间戳 是的,使数据库中的列没有时区,并始终存储从时刻开始的 UTC 时间。通过这种方式,您始终知道数据是什么,并且可以轻松处理它。演示也可以在您轻松选择的任何时区进行。 A) 始终使用类型 timestamptz。 B) 始终插入为 UTC,这是 PostgreSQL 始终自动理解的格式。如果您使用pg-promise,则默认情况下始终获得 UTC。 【参考方案1】:

最简单的方法是始终以 UTC 格式存储没有时区的时间戳。这样,使用它们进行显示和计算总是很容易。差异只是减法,直接比较。

如果该列是带有时区的时间戳,则无论如何输入都将转换为 UTC,但输出将处于当前设置的时区,如果设置不正确,则可能会显示错误的值。这也降低了数据库的效率。

在表示层中,时间戳可以显示在适当的时区,输入的值也可以转换为 UTC 进行存储。

这是处理时间戳的最简单、最有效和最灵活的方式。

使用 CURRENT_TIMESTAMP 将在执行时从服务器获取时间戳。

【讨论】:

我将列更新为没有时区,但是当我执行`insertArticle`时显示错误[error: date/time field value out of range: "1439715951000"] 这似乎是一个毫秒值,可能是 UNIX 纪元?然后你需要插入timestamp '1970-1-1' + interval '12357 seconds' 来实现一个实际的时间戳。当然数字转换为秒。 插入`时间戳'1970-1-1'+间隔'12357秒'`?你的意思是在数据库 sql 上执行这个 是的,而不是仅仅发送数字,如果时刻给出它的话,发送它的秒数。我对 moment/node.js 不熟悉,所以很遗憾无法给出最佳答案。我认为还有一种方法可以直接绑定时间戳/日期时间值。 如果我的服务器有时在欧洲或美国,这可行吗?我想要一个正确的日期,并且不依赖于服务器位置【参考方案2】:

没有时区的传入时间戳是在本地时间而不是 UTC 中解析的——我称之为 node-postgres 中的错误。无论如何,您可以通过添加以下代码来覆盖它以执行正确的操作:

pg.types.setTypeParser(1114, function(stringValue) 
    console.log(stringValue);
    return new Date(Date.parse(stringValue + "+0000"));
)

【讨论】:

感谢您的回答。我也在 seqlize.js 文档中看到了这段代码。但是我应该在哪里写这个函数?弄糊涂了! 只需将它添加到你的 node.js 源文件的顶部——在你调用 pg.connect 之前 只是给其他人的说明,我想实现同样的目标,但我的日期/时间列的类型为TIMESTAMP。使用上面的代码,其值为1184,而不是工作

以上是关于javascript + postgres:时区和时间戳的使用的主要内容,如果未能解决你的问题,请参考以下文章

Postgres中没有时区默认CURRENT_TIMESTAMP的字段TIMESTAMP的JPA模型类?

如何在 Postgres 9.3 中获取当前时区名称?

Postgres UTC时区vs当地时区

Rails 和 Postgres:迁移到 change_colomn 时出现错误“无法强制转换为没有时区的时间戳”

Postgres 通过时区转换防止时间戳

时区感知 postgres 查询为分钟、小时、天创建时间序列