【问题标题】:postgres: generate series of timestamps respecting time zonepostgres:生成一系列关于时区的时间戳
【发布时间】:2016-04-12 09:44:55
【问题描述】:

关于时区从夏令时更改为非夏令时的棘手问题让我感到困惑。

我正在尝试生成一系列时间戳,相隔 6 小时。稍后将其与数据集中每天 00、06、12、18 小时具有相应时间戳的数据相结合。

这可以正常工作,使用:

generate_series(extract(epoch from start_ts)::integer, extract(epoch from end_ts)::integer, 21600)

其中 start_ts 是第一个日期的 00 小时,而 end_ts 是最后一个日期的 00 小时,不包括。

但是,当时区偏移在系列中途从 +11 变为 +10 时,它将不再匹配任何记录,因为系列元素变为 1 小时。

有没有人建议如何生成一系列“纪元整数”或时间戳,以匹配 00、06、12、18 小时时间戳,同时尊重时区的偏移量?

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    这将生成它(使用 PostgreSQL 9.5+),从今天开始,持续 10 天:

    select (current_date::timestamp + ((a-1)||' days')::interval)::timestamptz
    from generate_series(1, 10, .25) a
    

    测试一整年:

    select *, date_part('hour', d::timestamp), d::timestamp
    from (
      select (current_date::timestamp + ((a-1)||' days')::interval)::timestamptz AS d
      from generate_series(1, 365, .25) a
      ) x
    where date_part('hour', d) not in (0, 6, 12, 18)
    

    编辑:以下版本适用于早于 9.5 的 PostgreSQL 版本:

    select (current_date::timestamp + (((a-1)/4.0)||' days')::interval)::timestamptz
    from generate_series(1, 4*  10  ) a  -- 10 days
    

    【讨论】:

    • 我喜欢!似乎我们使用的是 9.4,而不是 9.5,它在 generate_series 中引入了“数字”参数类型,在此之前只允许使用 int/bigint。我看看能不能升级。谢谢!但是,我确实设法以更冗长的方式解决了它。生成 2x 系列 - 1 前进 1 后退,然后验证每个结果。我也将作为解决方案发布,因为它还有其他一些好处to_timestamp(val) at time zone z
    • 抱歉,删除了勾号,因为进一步的测试表明,当时区更改为/从 DST 时,这不会考虑时区
    【解决方案2】:

    @Ziggy 的回答很棒,使用它。然而,这是我在我的应用程序中解决它的方法,它不能在 generate_series (v9.4) 中使用小数:

    _min timestamp with time zone, -- the first timestamp in the series
    _max timestamp with time zone, -- the last timestamp in the series
    _inc integer, -- the increment in seconds, eg 21600 (6hr)
    _tz text
    
    1. 使用 _max 的 tz 偏移量创建从 _max 向下的系列,
    2. 使用 _min 的 tz 偏移量创建从 _min 向上的系列,
    3. 合并结果
    4. 验证每个结果是否可以被结果 tz 中的 _inc 整除,否则丢弃

    查询:

    select t1 from (
        select ser,
            to_timestamp(ser) t1,
            extract(epoch from
                    to_timestamp(ser) at time zone _tz
                        - date_trunc('day', to_timestamp(ser) at time zone _tz)
                )::integer % _inc = 0 is_good
        from (
            select 'ser1' s, generate_series(extract(epoch from _min)::integer, extract(epoch from _max)::integer, _inc) ser
            union all
            select 'ser2' s, generate_series(extract(epoch from _max)::integer, extract(epoch from _min)::integer, _inc * -1) ser
        ) x
        group by ser, _tz, _inc
        order by ser asc
    ) x
    where is_good 
    ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-01
      • 1970-01-01
      • 2019-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-26
      • 2021-12-18
      相关资源
      最近更新 更多