【问题标题】:How to get a date from Postgres in my timezone如何在我的时区从 Postgres 获取日期
【发布时间】:2020-02-04 23:20:52
【问题描述】:

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

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

$ psql
> select localtimestamp;
2019-10-07 15:45:00.123456

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

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

在 CEST 12:00 插入一行:

> select "lastUpdate" from myTable;
2019-10-07 10:00:00.000000+00

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

Postgress 拥有所有信息:

> show timezone;
UCT
  • 它知道它在 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

有一种方法可以让我正确,那就是指定当前时区:

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

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

是否有其他语法可以正确执行此操作?

【问题讨论】:

  • 也许您应该尝试只使用timestamptz 类型而不是有时使用timestamp 类型。尝试将默认设置为now()。你的专栏是什么类型的?
  • 无论如何,select '2019-10-07 10:00:00.000000+00' at time zone 'CEST'; 对我来说很好用..(输出:2019-10-07 12:00:00
  • 如果您对类型和 AT TIME ZONE 运算符感到困惑,文档可能会有所帮助:postgresql.org/docs/current/…
  • 由于"lastUpdate"("lastUpdate" at time zone 'CEST') 在您给定的示例中都有一个时区,我想它有问题。

标签: postgresql nestjs typeorm


【解决方案1】:

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

timestamp 只存储没有时区的时间。 timestamp 存储 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

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

但这很脆弱。您必须确保它发生在每个连接上。您的应用程序依赖于数据库连接的特定配置。这是一个action-at-a-distance anti-pattern。格式化的原因并不明显,如果它被删除,很多看似无关的东西就会中断。

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

=> select timetz at time zone 'CEST' from demo;
      timezone       
---------------------
 2019-10-07 12:00:00

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

【讨论】:

  • 谢谢,使用 timestamptz 确实是简单的解决方案!
【解决方案2】:

在“美国/洛杉矶”时区“UTC”时区选择 created_at 来自用户;

【讨论】:

  • 选择 created_at at time zone 'utc' at time zone 'pst' from users;
  • 从 pg_timezone_names 中选择 *;
【解决方案3】:

从测试中选择 ts_tz AT TIME ZONE 'UTC';

【讨论】:

    猜你喜欢
    • 2016-08-23
    • 1970-01-01
    • 1970-01-01
    • 2023-01-30
    • 2021-03-26
    • 2013-10-04
    • 2016-10-21
    • 2021-03-11
    • 1970-01-01
    相关资源
    最近更新 更多