在PostgreSQL中,我们可以直接比较两个不同时区的时间戳吗?

Posted

技术标签:

【中文标题】在PostgreSQL中,我们可以直接比较两个不同时区的时间戳吗?【英文标题】:In PostgreSQL, can we directly compare two timestamp with different time zone? 【发布时间】:2016-07-27 15:07:02 【问题描述】:
SELECT * FROM table_a 
WHERE time_1 >= to_timestamp('11/01/2014 10:00 PDT', 'MM/DD/YYYY HH24:MI TZ')

time_1 是 UTC 时区,它是带有时区的时间戳。那么,这会给我我想要的还是我需要在函数 to_timestamp() 中执行准确的 UTC 时间?

【问题讨论】:

有一个很好的手册页可以帮助你顺便说一句:postgresql.org/docs/current/static/datatype-datetime.html 【参考方案1】:

Postgresql 有两种不同的时间戳数据类型,在什么时候应该使用哪一种令人困惑。这两种类型是:

timestamp(也称为timestamp without time zone)很可能是table_a中的类型 timestamp with time zone这是to_timestamp()返回的数据类型

您必须确保将苹果与苹果或一对与一对进行比较,不要将它们混合使用,否则您可能会得到不良结果。

如果您的table_a.time_1timestamp with time zone,那么您在问题中提供的代码将可以正常工作。

如果您的table_a.time_1timestamp,那么您将需要更改您的代码:

SELECT * 
  FROM table_a 
 WHERE time_1 >= to_timestamp('11/01/2014 10:00 PDT', 'MM/DD/YYYY HH24:MI TZ') at time zone 'utc';

最后一部分 (at time zone 'utc') 将从指定的时间戳中去除时区 (PDT),并将时间戳转换为 UTC。


编辑:在这个答案中帮助您的 cmets...

为了了解如何翻译时区,您需要了解两种形式的时间戳之间的区别。你会明白为什么你需要在下面理解这一点。正如我在上面指出的,两种形式的时间戳之间的区别令人困惑。有一个good manual page,但现在请继续阅读。

要了解的主要内容是 两个 版本实际上都没有存储时区(尽管有名称)。如果您添加一个额外的单词“translation”,命名会更有意义。想想“没有时区转换的时间戳”“有时区转换的时间戳”

timestamp with time zone翻译根本不存储时区。它旨在存储可能来自世界任何地方的时间戳,并且不会丢失它们的含义。因此,当输入一个时,您必须提供它来自的时区,否则 postgresql 将假定它来自the time zone of your current session。 Postgresql 自动将其从给定的时区转换为服务器的内部时区。你不需要知道那是什么时区,因为 postgresql 在给你值之前总是会从这个内部时区翻译回来。当您检索值(例如:SELECT my_time FROM foo)时,postgresql 会将时间戳转换为当前会话的时区。或者,您可以指定要转换为的时区(例如:SELECT my_time AT TIME ZONE 'PDT' FROM foo)。

考虑到这一点,更容易理解的是,timestamp没有时区转换从您指定的时间起永远不会更改。 Postgresql 会将11:00:00 视为发生在12:00:00 之前,即使您的意思是美国的11 个和英国的12 个。很容易看出为什么这可能不是您想要的。

一个非常常见的编程错误是认为timestamp with time zone 位于特定时区。它不是。它在您要求的任何时区。如果你没有指定你想要的时区,那么 postgresql 会假设你在当前会话时区想要它。

您已声明您的字段是timestamp with time zone,它们都位于UTC。这在技术上是不正确的。您的会话时区很可能是 UTC,因此 postgresql 会为您提供 UTC 格式的所有内容。

所以你有一个timestamp with time zone 并且你想知道这些时间在 PDT 中是什么时候?简单:SELECT my_time AT TIME ZONE 'PDT' FROM foo

了解AT TIME ZONE '...' 语法在timestamptimestamp with time zone 之间切换很重要。

timestamp AT TIME ZONE 'PDT' 转换为 timestamp with time zone 并告诉 postgresql 转换为 PDT 时区。 timestamp with time zone AT TIME ZONE 'PDT' 转换为 timestamp 告诉 postgresql 将其解释为来自“PDT”。

这种对称性意味着要反转AT TIME ZONE 'foo',您只需使用AT TIME ZONE 'foo'。换句话说,SELECT anything AT TIME ZONE 'PDT' AT TIME ZONE 'PDT' 将始终保持 anything 不变。

【讨论】:

感谢您的回答。在我的例子中,time_1 是带有时区的时间戳。 在这种情况下,您的代码将正常工作 :-) 不要添加我为使用 timestamp without time zone 而提供的额外代码 顺便说一句,如果我想在白天做一些计数,像 SELECT COUNT(*) FROM table_a GROUP BY DATE(time_1 at time zone 'PDT') 这样的东西会起作用吗? 只有当你的时间戳都对齐时才有效……1毫秒或1小时的差异会创建一个不同的组。您可以通过将时区格式化为日期 (to_char()) 进行分组,也可以在分组的单独字段中提取年、月、日。谷歌应该给你extract的语法。 我明白了。对于特定时间,它可能属于不同时区的不同日期。我只是想知道如何在DATE(to_char()) 之前将 time_1 从 UTC 转换为 PDT

以上是关于在PostgreSQL中,我们可以直接比较两个不同时区的时间戳吗?的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL比较两个jsonb对象

在不同系统中连接两个 postgreSQL 数据库时出错

PostgreSQL之SQL操作符介绍及实践

PostgreSQL之SQL操作符介绍及实践

如何在 POSTGRESQL 中从两个不同的数据库中检索数据

需要查询以列出两列相对相同的行,但需要注意 Postgresql