基本上你想要的是:
$ select starts_at AT TIME ZONE 'UTC' AT TIME ZONE 'US/Pacific' from schedules where id = 40
我从这篇文章中得到的解决方案如下,这是纯金!!!它非常清楚地解释了这个重要的问题,如果您想更好地了解 pstgrsql TZ 管理,请阅读它。
在本地时间表示没有区域的 PostgreSQL 时间戳
这是正在发生的事情。首先,您应该知道'PST 时区比 UTC 时区晚 8 小时,因此例如 2014 年 1 月 1 日下午 4:30 PST(2014 年 1 月 1 日星期三 16:00:30 -0800)相当于 2014 年 1 月 2 日 00:30上午 UTC(2014 年 1 月 2 日星期四 00:00:30 +0000)。PST 下午 4:00 之后的任何时间都会滑到第二天,解释为 UTC。
此外,正如 Erwin Brandstetter 上面提到的,postresql 有两种时间戳数据类型,一种有时区,一种没有。如果您的时间戳包含时区,那么一个简单的:
$ select starts_at AT TIME ZONE 'US/Pacific' from schedules where id = 40
将工作。但是,如果您的时间戳是无时区的,则执行上述命令将不起作用,您必须首先将您的无时区时间戳转换为带有时区的时间戳,即 UTC 时区,然后再将其转换为您想要的“PST”或“US/”太平洋”(在某些夏令时问题上是相同的。我认为你应该可以接受)。
让我用一个创建无时区时间戳的示例来演示。为方便起见,我们假设我们的本地时区确实是“PST”(如果不是,那么它会变得有点复杂,这对于本解释而言是不必要的)。
说我有:
$ select timestamp '2014-01-2 00:30:00' AS a, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AS b, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AT TIME ZONE 'PST' AS c, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d
这将产生:
"a"=>"2014-01-02 00:30:00" (This is the timezoneless timestamp)
"b"=>"2014-01-02 00:30:00+00" (This is the UTC TZ timestamp, note that up to a timezone, it is equivalent to the timezoneless one)
"c"=>"2014-01-01 16:30:00" (This is the correct 'PST' TZ conversion of the UTC timezone, if you read the documentation postgresql will not print the actual TZ for this conversion)
"d"=>"2014-01-02 08:30:00+00"
最后一个时间戳是在 postgresql 中将无时区时间戳从 UTC 转换为“PST”的所有混淆的原因。当我们写:
timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d
我们采用无时区时间戳并尝试将其转换为 'PST TZ(我们间接假设 postgresql 会理解我们希望它从 UTC TZ 转换时间戳,但 postresql 有自己的计划!)。在实践中,postgresql 所做的是它采用无时区时间戳('2014-01-2 00:30:00)并将其视为已经是“PST”TZ 时间戳(即:2014-01-2 00:30 :00 -0800) 并将其转换为 UTC 时区!!!所以它实际上将它提前 8 小时而不是向后推!因此我们得到 (2014-01-02 08:30:00+00)。
无论如何,最后一个(不直观的)行为是所有混乱的原因。如果您想要更彻底的解释,请阅读文章,实际上我得到的结果与最后一部分的结果有些不同,但总体思路是相同的。