【问题标题】:How is a timestamp with timezone read in PostgreSQL?如何在 PostgreSQL 中读取带有时区的时间戳?
【发布时间】:2019-01-02 08:11:12
【问题描述】:

假设我的 PostgreSQL 数据库中存储了一个带有时区的时间戳。像这样的:

2003-04-12 04:05:06.814191 America/New_York

在读取这些数据时,数据库会返回调整后的 GMT 时间以标准化所有读取的时间戳,还是直接按原样返回?

我问这个问题的原因是我创建了一个包含记录的表,其中每条记录都有一个时间戳列。我继续为不同的记录提供不同的时区。当我查询此表并尝试按时间戳列排序时,时区似乎对排序没有任何影响。这是设计使然吗?

我的结果示例:

1954-06-27 08:44:01.963454 Asia/Baghdad
1954-06-27 08:44:01.963454 GMT
1954-06-27 08:44:01.963454 Europe/Paris
1954-06-27 08:44:01.963454 Asia/Baghdad
1954-06-27 08:44:01.963454 America/New_York
1954-06-27 08:44:01.963454 America/New_York
1954-06-27 08:44:01.963454 America/New_York
1954-06-27 08:44:01.963454 GMT
1954-06-27 08:44:01.963454 America/New_York
1954-06-27 08:44:01.963454 America/New_York
1954-06-27 08:44:01.963454 Europe/Paris
1954-06-27 08:44:01.963454 America/New_York
1954-06-27 08:44:01.963454 Asia/Dhaka
1954-06-27 08:44:01.963454 GMT
1954-06-27 08:44:01.963454 GMT
1954-06-27 08:44:01.963454 Asia/Damascus
1954-06-27 08:44:01.963454 GMT
1954-06-27 08:44:01.963454 Asia/Damascus
1954-06-27 08:44:01.963454 America/New_York
1954-06-27 08:44:01.963454 Asia/Dhaka
1954-06-27 08:44:01.963454 Asia/Baghdad
1954-06-27 08:44:01.963454 Europe/Paris
1954-06-27 08:44:01.963454 Europe/Paris
1954-06-27 08:44:01.963454 Asia/Baghdad
1954-06-27 08:44:01.963454 Asia/Baghdad

所有这些记录的日期和时间都相同,不同的时区对排序没有影响。

为了更清楚,我实际上将这些时间戳作为字符串存储在名为 data 的 JSONb 列中,键为 datetime,即:

data = {
    "datetime" : "2003-04-12 04:05:06.814191 America/New_York",
    .....
}

在排序和过滤期间,我将其转换为时间戳。像这样的:

"(data->>'datetime')::timestamp"

【问题讨论】:

  • 没有时区数据与TIMEZONETZ 类型相关联——它只是一个瞬间。你能展示你是如何插入/选择你的示例数据的吗?
  • @teppic :抱歉,我之前忘了提一个重要细节。更新了问题。
  • 如果你投射到timestamp,这意味着timestamp without time zone,而不是timestamp with time zone

标签: postgresql datetime


【解决方案1】:

PostgreSQL 的“timestamp with time zone”类型实际上并没有在每条记录中存储时区偏移量。它只是在内部将所有内容标准化为 UTC。

“timestamp with time zone”的意义在于,因为存储的值是在已知时区中表示的,所以它明确地表示了一个特定的时间点。另一种选择,“没有时区的时间戳”是模棱两可的,因为它有一个时间,但没有说明它在哪个时区——记录可能是今天中午,但那个中午是在格林威治吗?中午在纽约?东京中午? “with time zone”类型避免了这个问题,因为该区域始终是格林威治。

(为了比较:我相信 Oracle 有一个“带有时区的时间戳”,它实际上在每条记录中存储了一个偏移量,以及一个“带有本地时区的时间戳”,它将所有内容标准化为服务器的时区,以避免必须存储每个记录-记录偏移量。PostgreSQL 的“timestamp with time zone”的命名与前者相似,但行为与后者相似。)


但是,听起来您实际上并没有在表中存储“带有时区的时间戳”;您本质上是在存储一个字符串,并作为select 的一部分转换为timestamptimestamp 关键字本身是指“无时区”变体(根据 SQL 标准的要求),PostgreSQL 文档说:

在已确定为timestamp without time zone 的文字中,PostgreSQL 将默默地忽略任何时区指示。也就是说,结果值是从输入值中的日期/时间字段派生的,并且不会针对时区进行调整。

我希望这同样适用于强制转换,但如果是这种情况,则不太清楚为什么您的输出(timestamp 值)包含 TZ 名称。但是您可能想改为转换为 timestamptz,或者创建一个单独的 timestamptz 列(以便可以对值进行索引)。


PostgreSQL documentation on date/time types 是一个很好的参考。

【讨论】:

  • 将其转换为timestamptz 解决了这个问题。谢谢。
猜你喜欢
  • 1970-01-01
  • 2015-08-27
  • 2019-06-25
  • 2021-12-26
  • 2013-03-27
  • 2014-01-24
  • 2013-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多