如何从 Postgres 获取我所在时区的日期

S. *_*ose 2 postgresql typeorm nestjs

我尝试在主机上使用 TypeORM 和 Postgres 部署 JS 应用程序。在本地,我有一个 Postgress DB,因此在我自己的 TZ 中运行。远程主机恰好将其系统时间设置为 UTC:

$ date
Mon Oct 7 15:45:00 UTC 2019

$ psql
> select localtimestamp;
2019-10-07 15:45:00.123456
Run Code Online (Sandbox Code Playgroud)

我有一个表,其中有自动更新的日期(意味着它会在记录更新时更新)。

// my.entity.ts
@UpdateDateColumn({type: 'timestamp', name: 'lastUpdate', default: () => 'LOCALTIMESTAMP' })
lastUpdate: Date;
Run Code Online (Sandbox Code Playgroud)

一行在 12:00 CEST 插入:

> select "lastUpdate" from myTable;
2019-10-07 10:00:00.000000+00
Run Code Online (Sandbox Code Playgroud)

我想获取我的时区 (CEST) 中的日期,无论服务器时间如何,因此它应该返回我 2019-10-07 12:00。我不喜欢硬编码任何技巧,因为它也应该在我的 CEST 机器上工作。

Postgress 拥有所有信息:

> show timezone;
UCT
Run Code Online (Sandbox Code Playgroud)
  • 它知道它在 UTC 时间运行
  • 我可以告诉它我想要哪个时区的日期

所以我希望很容易将其转换为我要求的格式。但是,我发现以下示例似乎不起作用:

> select ("lastUpdate" at time zone 'CEST') from myTable;
2019-10-07 08:00:00.000000+00

> select timezone('CEST', "lastUpdate") from myTable;
2019-10-07 08:00:00.000000+00
Run Code Online (Sandbox Code Playgroud)

有一种方法可以做到这一点,那就是指定当前时区:

> select ("lastUpdate" at time zone 'UTC' at time zone 'CEST') from myTable;
2019-10-07 12:00:00.000000
Run Code Online (Sandbox Code Playgroud)

然而,就像我说的,我不想对此进行硬编码(因为其他数据库在其他 TZ 上运行)并且 Postgres 知道它自己的时区。

还有另一种语法可以正确执行此操作吗?

Sch*_*ern 5

无论服务器配置如何,Postgres 中的所有时间戳都以 UTC 存储。认识到这一点很重要,与其他数据库不同,它不会将您的输入解释为本地时区。但是它会将其显示回其时区。

timestamp仅存储没有时区的时间。timestamptz存储 UTC 加上时区。

在时区设置为 UTC 的 Postgres 服务器上一起演示这些内容...

=> create table demo ( time timestamp, timetz timestamptz );
CREATE TABLE

=> insert into demo values ('2019-10-07 10:00', '2019-10-07 12:00 +0200');
INSERT 0 1

=> select * from demo;
        time         |         timetz         
---------------------+------------------------
 2019-10-07 10:00:00 | 2019-10-07 10:00:00+00
Run Code Online (Sandbox Code Playgroud)

timestamp忽略偏移量,仅存储 2019 年 10 月 7 日 10:00,无偏移量。虽然timestamptz存储 +0200 的偏移量,但以自己的 UTC 时区将时间显示给我。他们是同一时间点。


您可以将会话的数据库时区更改为 CEST。然后Postgres将在CEST中格式化timestamptz。

=> set time zone 'Antarctica/Troll';

=> select * from demo;
        time         |         timetz         
---------------------+------------------------
 2019-10-07 10:00:00 | 2019-10-07 12:00:00+02
Run Code Online (Sandbox Code Playgroud)

但这很脆弱。您必须确保它在每个连接上都发生。您的应用程序依赖于数据库连接的特定配置。这是一种远距离行动反模式。格式化的内容并不明显,如果删除它,许多看似不相关的东西就会被破坏。

相反,您应该在从数据库收到时间后根据需要重新格式化时间。您可以手动执行此操作...

=> select timetz at time zone 'CEST' from demo;
      timezone       
---------------------
 2019-10-07 12:00:00
Run Code Online (Sandbox Code Playgroud)

但通常这是您的 ORM 为您处理的事情。我不知道typeorm,但大多数都有一种一致地转换数据库类型的方法。您应该能够设置typeorm自动将 Postgres timestamptz 转换为您的本地应用程序时区。更好的是,它可以将其转换为适当的 Time 对象,而不是返回字符串,然后您可以完全控制该对象。