繁体   English   中英

generate_series 在夏令时变化 - 结果取决于服务器时区

[英]generate_series over daylight savings change - varied results depending on server timezone

当我的 postgres 服务器位于 America/New_York 时区,或者我使用SET SESSION TIME ZONE 'America/New_York' , generate_series 尊重夏令时的变化,我可以获得我想要的正确纪元或时间点:

postgres=# SET SESSION TIME ZONE 'America/New_York';
SET
postgres=#
postgres=# with seq(ts) as (select * from generate_series('2018-11-03 00:00:00.000 -04:00', '2018-11-06 13:40:39.067 -05:00', '1d'::interval))
postgres-# select ts, extract(epoch from ts) as epoch, ts at time zone 'America/New_York' as eastern
postgres-# from seq;
           ts           |   epoch    |       eastern
------------------------+------------+---------------------
 2018-11-03 00:00:00-04 | 1541217600 | 2018-11-03 00:00:00
 2018-11-04 00:00:00-04 | 1541304000 | 2018-11-04 00:00:00
 2018-11-05 00:00:00-05 | 1541394000 | 2018-11-05 00:00:00
 2018-11-06 00:00:00-05 | 1541480400 | 2018-11-06 00:00:00
(4 rows)

但是当我的服务器在生产中使用 UTC 时, generate_series 不遵守夏令时更改:

postgres=# SET SESSION TIME ZONE 'UTC';
SET
postgres=# with seq(ts) as (select * from generate_series('2018-11-03 00:00:00.000 -04:00', '2018-11-06 13:40:39.067 -05:00', '1d'::interval))
postgres-# select ts, extract(epoch from ts) as epoch, ts at time zone 'America/New_York' as eastern
postgres-# from seq;
           ts           |   epoch    |       eastern
------------------------+------------+---------------------
 2018-11-03 04:00:00+00 | 1541217600 | 2018-11-03 00:00:00
 2018-11-04 04:00:00+00 | 1541304000 | 2018-11-04 00:00:00
 2018-11-05 04:00:00+00 | 1541390400 | 2018-11-04 23:00:00
 2018-11-06 04:00:00+00 | 1541476800 | 2018-11-05 23:00:00
(4 rows)

通知 11/4 和 11/5 尚未针对 DST 更改进行调整。

有什么办法可以解决这个问题而不在查询时设置会话时区?

使用 postgres 9.6 ...

会话时区是控制如何解释1天间隔的原因,所以我认为您的问题的答案很简单,不是。

Postgres文档对此进行了如下解释:

当向带有时区值的时间戳添加间隔值(或从中减去间隔值)时,天组件将带时区的时间戳记的日期提前或减少指定的天数。 跨夏令时更改(将会话时区设置为可识别DST的时区),这意味着interval '1 day'不一定等于interval '24 hours' 例如,将会CST7CDT时区设置为CST7CDTtimestamp with time zone '2005-04-02 12:00-07' + interval '1 day' timestamp with time zone '2005-04-03 12:00-06'将产生timestamp with time zone '2005-04-03 12:00-06' ,同时将interval '24 hours'添加到具有时区的同一初始时间戳时,将生成timestamp with time zone '2005-04-03 13:00-06' ,因为夏时制时间在2005-04-03 02:00在时区CST7CDT

据我所知,除了将其设置为会话时区外,没有其他机制可以告诉特定时间段要解释的时间间隔。 换句话说,我想您会在寻找类似'1 day tz America/New_York'::interval ,但我不相信这样的语法存在。

您可以在连接时自动为特定用户(ALTER USER)或特定数据库(ALTER DATABASE)设置时区。

我能想到的唯一其他方法是使用函数。

BEGIN;

CREATE FUNCTION f1() RETURNS SETOF timestamptz
AS $$
SELECT generate_series('2018-11-03 00:00:00-04', '2018-11-06 00:00:00-05', interval '1 day');
$$
LANGUAGE sql
SET timezone = 'America/New_York';                                                                                                               

SET timezone = 'UTC';
SELECT generate_series('2018-11-03 00:00:00-04', '2018-11-06 00:00:00-05', interval '1 day');
SELECT * FROM f1();

ROLLBACK;

生产:

    generate_series
------------------------
 2018-11-03 04:00:00+00
 2018-11-04 04:00:00+00
 2018-11-05 04:00:00+00
 2018-11-06 04:00:00+00
(4 rows)

           f1
------------------------
 2018-11-03 04:00:00+00
 2018-11-04 04:00:00+00
 2018-11-05 05:00:00+00
 2018-11-06 05:00:00+00
(4 rows)

您可以尝试在所需时区生成系列,然后转换为 UTC:

select generate_series('2018-11-03 00:00:00.000', '2018-11-06 13:40:39.067', '1d'::interval)::timestamp at time zone 'America/New_York'

输出:

2018-11-03 04:00:00+00
2018-11-04 04:00:00+00
2018-11-05 05:00:00+00
2018-11-06 05:00:00+00

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM