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

时间:2016-04-06 23:45:01

标签: sql postgresql timezone timestamp

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时间?

1 个答案:

答案 0 :(得分:2)

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。

编辑:在此回答中帮助您发表评论......

为了理解如何翻译时区,您需要了解两种时间戳形式之间的区别。很明显为什么你需要在下面理解这一点。如上所述,两种形式的时间戳之间的差异令人困惑。有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不变。