1

我正在尝试在 Postgres 中创建一个表,该表存储在接下来的几年中每天每整小时发生一次的事件。所以我使用以下表达式填充了一个列:

INSERT INTO tablename(time) 
SELECT CAST('2013-01-01' AS DATE) + (n || ' hour')::INTERVAL 
 FROM generate_series(0, 100000) n;

作为本专栏的数据类型,我选择了带时区的时间戳,并希望通过这种方式自动考虑夏令时。(顺便说一句,我的默认时区是 CET,所以适用 DST 时是 UTC+1 或 UTC+2)。作为上述查询的结果,我得到了这个:

  • 2013-03-31 00:00:00 +01
  • 2013-03-31 01:00:00 +01
  • 2013-03-31 03:00:00 +02
  • 2013-03-31 03:00:00 +02
  • 2013-03-31 04:00:00 +02
  • ...
  • 2013-10-27 00:00:00 +02
  • 2013-10-27 01:00:00 +02
  • 2013-10-27 02:00:00 +01
  • 2013-10-27 03:00:00 +01
  • 2013-10-27 04:00:00 +01
  • ...

UTC 的偏移量发生了变化,我预计 02:00 会在 3 月 31 日被忽略,因为这一天只有 23 小时,但我不知道为什么 03:00 有两次,而 10 月 27 日的 02:00 只有一次而不是两次,因为这一天有 25 小时。我想要实现的是,在 3 月 2 点的特定日期的所有年份都不会被跳过(我宁愿输入 'na' 或相应的值),并且 3'oclock 有两个条目在 10 月的特定日期(但不是 3 月),这样我将获得以下形式的列(其中 1 代表 00:00-1:00 的小时,2 代表 1:00-2:00 , ETC。):

  • 2013-03-31 1 +01
  • 2013-03-31 2 +01
  • 2013-03-31 3 +02
  • 2013-03-31 4 +02
  • 2013-03-31 5 +02
  • ...
  • 2013-10-27 1 +02
  • 2013-10-27 2 +02
  • 2013-10-27 3A +02
  • 2013-10-27 3B +01
  • 2013-10-27 4 +01
  • 2013-10-27 5 +01
  • ...

有人知道如何去做吗?我做错了什么吗?只是格式的问题吗?我必须写一个函数吗?任何帮助,将不胜感激。谢谢你。

4

2 回答 2

0

Postgres 中的日期和时间以 UTC 存储,并根据时区配置指定的区域转换为本地时间。

这意味着您只需要解决表示问题。尝试使用AT TIME ZONE 'UTC+2'将 UTC 时间转换为您的时区并查看结果。这是查询:

SELECT (CAST('2013-03-30' AS DATE) + (n || ' hour')::INTERVAL) AT TIME ZONE 'UTC+2' 
    FROM generate_series(0, 1000) n;
于 2014-03-16T19:15:20.187 回答
0

无论时区设置如何,时间戳始终存储为 UTC。从手册

对于带时区的时间戳,内部存储的值始终采用 UTC(通用协调时间,传统上称为格林威治标准时间,GMT)。使用该时区的适当偏移量将具有指定明确时区的输入值转换为 UTC。如果输入字符串中没有说明时区,则假定它位于系统的 TimeZone 参数指示的时区中,并使用时区的偏移量转换为 UTC。

set time zone 'CET';

drop table if exists events;
create table events (
    tstz timestamp with time zone
);
insert into events (tstz)
select generate_series('2013-01-01', '2013-10-28', interval '1 hour') s(tstz)
;

注意generate_series函数的使用。

select
    tstz at time zone 'UTC' as "UTC",
    tstz at time zone 'CET' as "CET",
    tstz at time zone 'CEST' as "CEST",
    tstz as "LOCAL"
from events
where date_trunc('day', tstz) in ('2013-03-31', '2013-10-27')
order by tstz
;
         UTC         |         CET         |        CEST         |         LOCAL          
---------------------+---------------------+---------------------+------------------------
 2013-03-30 23:00:00 | 2013-03-31 00:00:00 | 2013-03-31 01:00:00 | 2013-03-31 00:00:00+01
 2013-03-31 00:00:00 | 2013-03-31 01:00:00 | 2013-03-31 02:00:00 | 2013-03-31 01:00:00+01
 2013-03-31 01:00:00 | 2013-03-31 02:00:00 | 2013-03-31 03:00:00 | 2013-03-31 03:00:00+02
 2013-03-31 02:00:00 | 2013-03-31 03:00:00 | 2013-03-31 04:00:00 | 2013-03-31 04:00:00+02
 2013-03-31 03:00:00 | 2013-03-31 04:00:00 | 2013-03-31 05:00:00 | 2013-03-31 05:00:00+02
...
 2013-10-26 22:00:00 | 2013-10-26 23:00:00 | 2013-10-27 00:00:00 | 2013-10-27 00:00:00+02
 2013-10-26 23:00:00 | 2013-10-27 00:00:00 | 2013-10-27 01:00:00 | 2013-10-27 01:00:00+02
 2013-10-27 00:00:00 | 2013-10-27 01:00:00 | 2013-10-27 02:00:00 | 2013-10-27 02:00:00+02
 2013-10-27 01:00:00 | 2013-10-27 02:00:00 | 2013-10-27 03:00:00 | 2013-10-27 02:00:00+01
 2013-10-27 02:00:00 | 2013-10-27 03:00:00 | 2013-10-27 04:00:00 | 2013-10-27 03:00:00+01
 2013-10-27 03:00:00 | 2013-10-27 04:00:00 | 2013-10-27 05:00:00 | 2013-10-27 04:00:00+01
 2013-10-27 04:00:00 | 2013-10-27 05:00:00 | 2013-10-27 06:00:00 | 2013-10-27 05:00:00+01

如果一个timestamp with timestamp列是 selectec 而没有使用上面at time zoneLOCAL列,它将在该时间戳的服务器时区输出。这就是为什么会有缺失和重复的时间。

我认为你想要的输出是错误的。但是可以通过一些查询来实现

我无法重现您的实际输出。服务器时区是什么?

show time zone;
 TimeZone 
----------
 CET
于 2014-03-16T19:19:26.750 回答