生成gmt中所有分钟的日期并获取其本地值

时间:2018-02-01 20:36:18

标签: sql postgresql timezone dst

我开始相信我所追求的东西根本不可能使用postgresql:

我希望每个GMT在指定日期的分钟数,并在同一个表格中获得与timestamp without time zone相同的本地版本。

到目前为止,我能够获得GMT和一些完全错误的偏移。 (每次尝试注入时区时,我都无法更改SET TIME ZONE 'Europe/Paris' +1h

CREATE TABLE to_do ("id" int, "tz_lib" varchar(16));
CREATE TABLE date_needed ("date_lib" date);

SQL Fiddle

查询3

insert into t1(id,tz_lib,date_gmt, date_local)
select 
  id,
  tz_lib,
  date_lib + (seq ||'minute')::interval AS date_gmt, 
  (date_lib + (seq ||'minute')::interval) at time zone tz_lib AS date_local
from  date_needed
cross join to_do
cross join generate_series(0,1439) AS seq

Results

| id |           tz_lib |             date_gmt |           date_local |
|----|------------------|----------------------|----------------------|
|  1 | Pacific/Auckland | 2018-01-15T00:00:00Z | 2018-01-14T12:00:00Z |
|  2 |     Europe/Paris | 2018-01-15T00:00:00Z | 2018-01-15T00:00:00Z |
|  3 |   Asia/Hong_Kong | 2018-01-15T00:00:00Z | 2018-01-14T17:00:00Z |
|  1 | Pacific/Auckland | 2018-01-15T00:01:00Z | 2018-01-14T12:01:00Z |
|  2 |     Europe/Paris | 2018-01-15T00:01:00Z | 2018-01-15T00:01:00Z |
|  3 |   Asia/Hong_Kong | 2018-01-15T00:01:00Z | 2018-01-14T17:01:00Z |
|  1 | Pacific/Auckland | 2018-01-15T00:02:00Z | 2018-01-14T12:02:00Z |
|  2 |     Europe/Paris | 2018-01-15T00:02:00Z | 2018-01-15T00:02:00Z |
|  3 |   Asia/Hong_Kong | 2018-01-15T00:02:00Z | 2018-01-14T17:02:00Z |
|  1 | Pacific/Auckland | 2018-01-15T00:03:00Z | 2018-01-14T12:03:00Z |

使用INTERVAL小心回答,因为它们不是DST意识到的,并且半年都会出错(遗憾的是......)

结果不错,方法不好:

目前,我发现获得例外结果的唯一方法是将服务器时区更改为GMT并强制转换date_local:

我无法使用此解决方案来处理我的案例......

查询1

SET TIME ZONE 'GMT'

insert into t1(id,tz_lib,date_gmt, date_local)
select 
  id,
  tz_lib,
  date_lib + (seq ||'minute')::interval AS date_gmt, 
  (date_lib + (seq ||'minute')::interval)::timestamptz at time zone tz_lib AS date_local
from  date_needed
cross join to_do
cross join generate_series(0,1439) AS seq

结果(& Expected one)

| id |           tz_lib |             date_gmt |           date_local |
|----|------------------|----------------------|----------------------|
|  1 | Pacific/Auckland | 2018-01-15T00:00:00Z | 2018-01-15T13:00:00Z |
|  2 |     Europe/Paris | 2018-01-15T00:00:00Z | 2018-01-15T01:00:00Z |
|  3 |   Asia/Hong_Kong | 2018-01-15T00:00:00Z | 2018-01-15T08:00:00Z |
|  1 | Pacific/Auckland | 2018-01-15T00:01:00Z | 2018-01-15T13:01:00Z |
|  2 |     Europe/Paris | 2018-01-15T00:01:00Z | 2018-01-15T01:01:00Z |
|  3 |   Asia/Hong_Kong | 2018-01-15T00:01:00Z | 2018-01-15T08:01:00Z |
|  1 | Pacific/Auckland | 2018-01-15T00:02:00Z | 2018-01-15T13:02:00Z |
|  2 |     Europe/Paris | 2018-01-15T00:02:00Z | 2018-01-15T01:02:00Z |
|  3 |   Asia/Hong_Kong | 2018-01-15T00:02:00Z | 2018-01-15T08:02:00Z |
|  1 | Pacific/Auckland | 2018-01-15T00:03:00Z | 2018-01-15T13:03:00Z |

1 个答案:

答案 0 :(得分:1)

我的解决方案是在整个过程中使用timestamp without time zone

SELECT to_do.id,
       to_do.tz_lib,
       seq.seq AS date_gmt,
       seq.seq AT TIME ZONE 'UTC' AT TIME ZONE to_do.tz_lib AS date_local
FROM to_do
   CROSS JOIN date_needed
   CROSS JOIN LATERAL
      generate_series(
         date_needed.date_lib::timestamp,
         date_needed.date_lib::timestamp + INTERVAL '1439 minutes',
         INTERVAL '1 minute'
      ) seq;

说明:seq将传递UTC时间戳。使用AT TIME ZONE 'UTC',我将其正确转换为timestamp with time zone,然后使用第二个AT TIME ZONE,我会看到当时该时区显示的内容。