Mat*_*ner 43 postgresql timezone datetime rails-postgresql postgresql-9.1
我在从Postgres正确选择日期时遇到问题 - 它们以UTC格式存储,但未正确转换为Date()函数.
将时间戳转换为日期会给我错误的日期,如果它超过太平洋标准时间下午4点.
2012-06-21
应该是2012-06-20
这种情况.
该starts_at
列数据类型是timestamp without time zone
.这是我的疑问:
无需转换为PST时区:
Select starts_at from schedules where id = 40;
starts_at
---------------------
2012-06-21 01:00:00
Run Code Online (Sandbox Code Playgroud)
转换给出了这个:
Select (starts_at at time zone 'pst') from schedules where id = 40;
timezone
------------------------
2012-06-21 02:00:00-07
Run Code Online (Sandbox Code Playgroud)
但是都没有转换为时区中的正确日期.
Erw*_*ter 34
我没有看到你问题的确切类型starts_at
.你真的应该包含这些信息,这是解决方案的关键.我不得不猜.
基本上,PostgreSQL 总是在timestamp with time zone
内部存储该类型的UTC时间值.只有显示屏因当前timezone
设置而异.AT TIME ZONE
构造的效果也随基础数据类型而变化.更多细节:
如果date
从类型中提取timestamp [without time zone]
,则会获得当前时区的日期.输出中的日期与timestamp
值的显示中的日期相同.
如果date
从类型中提取timestamp with time zone
(timestamptz
简称),则首先"应用"时区偏移.您仍然可以获得当前时区的日期,这与时间戳的显示一致.同一时间点转换为欧洲部分地区的第二天,例如在加利福尼亚州的下午4点过去.要获取特定时区的日期,AT TIME ZONE
请先申请.
因此,您在问题的顶部描述的内容与您的示例相矛盾.
鉴于这starts_at
是a timestamp [without time zone]
并且服务器上的时间设置为本地时间.测试:
SELECT now();
Run Code Online (Sandbox Code Playgroud)
它与墙上的时钟显示的时间相同吗?如果是(并且数据库服务器以正确的时间运行),则timezone
当前会话的设置与您的本地时区一致.如果不是,您可能需要访问timezone
您postgresql.conf
或您的客户的会话设置.手册中的详细信息.
请注意,timezone
偏移量使用时间戳文字中显示的相反符号.看到:
要获得当地的日期starts_at
只是
SELECT starts_at::date
Run Code Online (Sandbox Code Playgroud)
无异于:
SELECT date(starts_at)
Run Code Online (Sandbox Code Playgroud)
顺便说一下,你现在的时间是UTC-7,而不是UTC-8,因为夏令时有效(不是人类更明智的想法).
太平洋标准时间(PST)通常timestamp
比UTC(通用时区)早8小时(更大的值),但在夏令时期间(如现在),它可以是7小时.这就是为什么timestamptz
显示2012-06-21 02:00:00
-07
在你的例子中.该构造AT TIME ZONE 'PST'
考虑了夏令时.这两个表达式会产生不同的结果(一个在冬天,一个在夏天),并且可能会在演员时产生不同的日期:
SELECT '2012-06-21 01:00:00'::timestamp AT TIME ZONE 'PST'
, '2012-12-21 01:00:00'::timestamp AT TIME ZONE 'PST'
Run Code Online (Sandbox Code Playgroud)
Ami*_*itF 33
基本上你想要的是:
$ select starts_at AT TIME ZONE 'UTC' AT TIME ZONE 'US/Pacific' from schedules where id = 40
Run Code Online (Sandbox Code Playgroud)
我从这篇文章得到的解决方案如下,这是直的黄金!它非常清楚地解释了这个非平凡的问题,如果你想更好地理解pstgrsql TZ管理,请给它一个读.
这是正在发生的事情.首先你应该知道'PST时区比UTC时区落后8小时,所以例如2014年1月1日,太平洋标准时间下午4:30(2014年1月1日星期三16:00:30 - 0800)相当于2014年1月2日,00:30上午UTC(星期四,2014年1月2日00:00:30 +0000).太平洋标准时间下午4点之后的任何时间滑到第二天,解释为UTC.
另外,正如上面提到的Erwin Brandstetter,postresql有两种类型的时间戳数据类型,一种带有时区,一种带有时区.如果您的时间戳包含时区,那么简单:
$ select starts_at AT TIME ZONE 'US/Pacific' from schedules where id = 40
Run Code Online (Sandbox Code Playgroud)
将工作.但是,如果您的时间戳是无时区的,执行上述命令将不起作用,您必须首先将您的无时区时间戳转换为带有时区的时间戳,即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
Run Code Online (Sandbox Code Playgroud)
这将产生:
"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"
Run Code Online (Sandbox Code Playgroud)
最后一个时间戳是在postgresql中将无时区时间戳从UTC转换为'PST'的所有混淆的原因.当我们写:
timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d
Run Code Online (Sandbox Code Playgroud)
我们正在采用无时区的时间戳并尝试将其转换为'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).
无论如何,这最后(不直观)的行为是导致所有混乱的原因.阅读文章如果你想要更全面的解释,我实际上得到的结果与他们在最后一部分有点不同,但总体思路是一样的.
小智 8
我知道这是一个旧版本,但您可能需要考虑使用AT TIME ZONE"US/Pacific"进行投射以避免任何PST/PDT问题.所以
SELECT starts_at :: TIMESTAMPTZ AT TIME ZONE"US/Pacific"FROM schedule WHERE ID ='40';
归档时间: |
|
查看次数: |
67570 次 |
最近记录: |