Postgres timestamptz列和用户的时区

时间:2016-07-25 10:38:35

标签: postgresql datetime timezone timestamp-with-timezone

将表更改为对所有时间列使用timestamptz后,根据时间范围进行选择时,我会看到非常奇怪的行为。当用户的时区是UTC时,它可以工作,结果是正确的。当用户的时区不是UTC时,结果为零。我希望结果不应该取决于用户的时区。

set timezone = 'UTC';

select count(*) 
from table1
where modified >= timestamp '2016-07-25 08:00' at time zone 'GB'
  and modified <  timestamp '2016-07-25 09:00' at time zone 'GB'
;

set timezone = 'GB';

select count(*) 
from table1
where modified >= timestamp '2016-07-25 08:00' at time zone 'GB'
  and modified <  timestamp '2016-07-25 09:00' at time zone 'GB'
;

在查询解释中,我看到Postgres正确转换时间常数。在第一种情况(UTC)中显示

'2016-07-25 07:00:00+00'::timestamp with timezone 
'2016-07-25 08:00:00+00'::timestamp with timezone

第二种情况(GB)显示

'2016-07-25 08:00:00+01'::timestamp with timezone 
'2016-07-25 09:00:00+01'::timestamp with timezone

更奇怪的是,只有当时差为一小时时,它才能完全发挥作用。当我过滤两个小时,从早上8点到上午10点,查询返回非零结果。它像这样工作

count(*) from 08:00 to 09:00 - zero
count(*) from 09:00 to 10:00 - zero
count(*) from 08:00 to 10:00 = actual count from 09:00 to 10:00

看起来范围转换中存在错误。转换开始时间但不结束开始时间。

我想知道以前是否有人看过这个问题。 Postgres是9.3.4,在Ubuntu上运行。

modified列的定义

...
modified timestamp with time zone NOT NULL DEFAULT now(),
...

EXPLAIN

Aggregate  (cost=374.84..374.85 rows=1 width=0)
  Output: count(*)
  ->  Index Only Scan using modified_idx on public.table1  (cost=0.56..362.14 rows=5079 width=0)
        Output: modified
        Index Cond: ((table1.modified >= '2016-07-25 08:00:00+01'::timestamp with time zone) AND (table1.modified < '2016-07-25 09:00:00+01'::timestamp with time zone))

1 个答案:

答案 0 :(得分:0)

这似乎是不可能的,我想到的唯一解释是索引已损坏。

REINDEX INDEX modified_idx;

将重建索引,希望这将解决问题。