Postgresql to_timestamp在包装extract()时返回不同的日期

时间:2013-12-06 11:51:48

标签: sql postgresql

导入脚本略有错误,导致时间戳插入1000倍。然而,使用to_timestamp和extract()会导致约一个月的日期,即使中间数字和转换看起来是正确的。

1)
select start_time from matches order by match_id limit 1;

  | timestamp without time zone
----------------------
1 | 1970-01-16 11:29:18.352


2)
select (extract(epoch from start_time) * 1000)
  from matches order by match_id limit 1;

  | double precision
----------------------
1 | 1333758352


3)
select to_timestamp(1333758352) at time zone 'UTC';

  | timestamp without time zone
----------------------
1 | 2012-04-07 00:25:52


4)
select (to_timestamp(extract(epoch from start_time) * 1000) at time zone 'UTC')
  from matches order by match_id limit 1;

  | timestamp without time zone
----------------------
1 | 2012-05-18 16:25:52

1)显示时间戳列中的当前数据,2)和3)显示正在执行的正确数字和转换,但在4)中的一个查询中放在一起,日期最终偏移超过一个月。

我对这个问题感到困惑,因为组件单独工作,而to_timestamp中的简单数学也适用于我尝试过的其他情况。


再现(PostgreSQL 9.3.1):

create table test_table ( t timestamp );
insert into test_table VALUES ('1970-01-16 11:29:18.352');
select (extract(epoch from t) * 1000) from test_table;
select to_timestamp(1333758352) at time zone 'UTC';
select (to_timestamp(extract(epoch from t) * 1000) at time zone 'UTC') from test_table;

SqlFiddle:http://sqlfiddle.com/#!15/12f6f/1/0

在SqlFiddle上,它适用于8.4,但在9.3上失败。


决议和原因

这里的天真方法遇到了一个边缘情况,我们最终将时区偏移量与原始日期相乘一小时。因此结果是1000小时的偏移(由于我在GMT)。将非UTC时间转换为具有时区会丢弃GMT转换,从而使日期的奇数乘法按预期进行。

所以,extract(epoch from t::timestamp with time zone)在对结果进行原始数学运算然后将其放回时间戳时。{/ p>

1 个答案:

答案 0 :(得分:2)

8.x和9.x版本之间的行为肯定存在差异。 (fiddle

select 
    start_time
  , extract(epoch from start_time) * 1000 as epoch_start_time
  , to_timestamp(1337358352) at time zone 'UTC' as to_timestamp_int
  , to_timestamp(extract(epoch from start_time) * 1000) at time zone 'UTC' as to_timestamp_expression
from matches;

8.x显示您的行为。 9.x显示我的“无法重现”行为。 (您可以在SQLfiddle的工具栏中切换版本。)