PostgreSQL date() with timezone
我在从Postgres正确选择日期时遇到了一个问题-这些日期存储在UTC中,但是未正确使用date()函数进行转换。
如果时间戳超过太平洋标准时间下午4点,那么将时间戳转换为日期会给出错误的日期。
在这种情况下,
不转换为PST时区:
1 2 3 4 5 | SELECT starts_at FROM schedules WHERE id = 40; starts_at --------------------- 2012-06-21 01:00:00 |
转换可以得到:
1 2 3 4 | SELECT (starts_at at TIME zone 'pst') FROM schedules WHERE id = 40; timezone ------------------------ 2012-06-21 02:00:00-07 |
但两者都不能转换为时区中的正确日期。
基本上你想要的是:
1 | $ 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(星期三,2014年1月1日16:00:30-0800)相当于2014年1月2日上午00:30(星期四,2014年1月2日00:00:30+0000)。太平洋标准时间下午4:00之后的任何时间都会延迟到第二天,即UTC。
另外,正如上面提到的ErwinBrandstetter,postresql有两种类型的时间戳数据类型,一种带有时区,另一种没有时区。如果您的时间戳包括时区,那么简单的:
1 | $ SELECT starts_at AT TIME ZONE 'US/Pacific' FROM schedules WHERE id = 40 |
会工作。但是,如果时间戳是无时区的,则执行上述命令将不起作用,并且必须首先将无时区时间戳转换为具有时区(即UTC时区)的时间戳,然后将其转换为所需的"pst"或"us/pacific"(在某些夏令时问题上是相同的)。我想你也可以。
让我用一个创建无时区时间戳的示例来演示。为了方便起见,假设我们的本地时区确实是"pst"(如果不是,那么它会变得稍微复杂一点,这对于解释来说是不必要的)。
说我有:
1 | $ 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 |
这将产生:
1 2 3 4 | "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"的所有混淆的原因。当我们写:
1 | 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)。
总之,最后一个(不直观的)行为是所有混乱的原因。读这篇文章,如果你想更深入的解释,我实际上得到的结果与上一部分的结果有点不同,但总的想法是一样的。
在你的问题中,我看不到确切类型的
基本上,PostgreSQL总是在内部存储
- 在Rails和PostgreSQL中完全忽略时区
如果从类型
如果从类型
因此,你在问题顶部所描述的与你的例子相矛盾。
假设
1 | SELECT now(); |
它和墙上的钟显示的时间一样吗?如果是(并且DB服务器以正确的时间运行),则当前会话的
请注意,
- Postgres数据库中的特殊时区处理
从
1 | SELECT starts_at::DATE |
等于:
1 | SELECT DATE(starts_at) |
顺便说一句,你的当地时间是现在的UTC-7,而不是UTC-8,因为夏令时是有效的(不是人类最聪明的想法之一)。
太平洋标准时间(pst)通常比UTC(通用时区)早8小时(更大的
1 2 | SELECT '2012-06-21 01:00:00'::TIMESTAMP AT TIME ZONE 'PST' , '2012-12-21 01:00:00'::TIMESTAMP AT TIME ZONE 'PST' |
我知道这是一个旧版本,但您可能想考虑在广播时使用时区"美国/太平洋",以避免任何PST/PDT问题。所以
select从id='40'的日程表开始在时区"US/Pacific"的时间戳"U at::Timestamptz";