问题描述
我在 Netezza 数据库中工作,该数据库将时间存储为 GMT(或者我们的数据工程师告诉我)。我需要能够将其转换为中央标准时间 (CST),但要考虑夏令时。我发现我可以使用类似的东西:
SELECT CURRENT_TIMESTAMP,CURRENT_TIMESTAMP AT TIME ZONE 'CST' AT TIME ZONE 'GMT'
但是,当我运行这个 SELECT 时(请记住,今天是 2021 年 3 月 30 日 - CST 应该与 GTM 仅相差 5 小时),我得到了 6 小时的差异......我查了一个参考Netezza 中有哪些时区可用,我看到一个 5 小时的“CDT”,这适用于 5 小时的差异,但这意味着在我的查询中,我需要在每次 DST 切换时更改此设置或执行某种操作详细的 case 语句,以根据一年中的日期/时间知道使用哪个。
是否有一种简单的自动化方法可以将 GTM 时间转换为中央标准时间以考虑夏令时?非常感谢!!!
解决方法
这个问题可以解释为两种方式之一。在这两种情况下,解决方案是根据时间戳是否介于 3 月第二个星期日凌晨 2 点和 11 月第一个星期日凌晨 2 点之间(美国中部时区)来确定要转换到的时区
- 表中的时间戳,需要根据当前时间(查询运行时)转换为
CST
或CDT
- 这意味着如果相同的查询在 2 月份运行,结果将与 现在运行
- 也会根据 netezza 系统的时区设置而有所不同
例如
select
t as original,-- extract year from current date and 2nd Sunday of March
-- use last_day to make sure we account for March 1 being a Sunday
(next_day(next_day(
last_day((date_part('years',current_date) || '-02-01'):: date),'sun'),'sun')|| ' 02:00:00'):: timestamp as dstart,-- extract year from current date and 1st Sunday of Nov
-- use last_day to make sure we account for Nov 1 being a Sunday
(next_day(last_day(
(date_part('years',current_date) || '-10-01')::date),'sun')|| ' 02:00:00'):: timestamp as dend,case when current_timestamp between dstart
and dend then 'CDT' else 'CST' end as tz,t at time zone tz as converted
from
tdata;
会产生
ORIGINAL | DSTART | DEND | TZ | CONVERTED
---------------------+---------------------+---------------------+-----+------------------------
2021-01-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CDT | 2021-01-01 12:00:00-05
2021-04-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CDT | 2021-04-01 12:00:00-05
2020-04-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CDT | 2020-04-01 12:00:00-05
2020-12-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CDT | 2020-12-01 12:00:00-05
(4 rows)
或
- 表中的时间戳需要转换为
CST
或CDT
,具体取决于夏令时在时间戳中定义的相应year
中的开始/结束时间。- 这更具确定性
select
t as original,-- extract year from this timestamp and 2nd Sunday of March
-- use last_day to make sure we account for March 1 being a Sunday
(next_day(next_day(
last_day((date_part('years',t) || '-02-01'):: date),-- extract year from this timestamp and 1st Sunday of Nov
-- use last_day to make sure we account for Nov 1 being a Sunday
(next_day(last_day((date_part('years',t) || '-10-01')::date),t at time zone tz as converted
from
tdata;
这将产生(tdata 是一个带有 4 个时间戳的示例表)
ORIGINAL | DSTART | DEND | TZ | CONVERTED
---------------------+---------------------+---------------------+-----+------------------------
2021-01-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CST | 2021-01-01 11:00:00-06
2021-04-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CDT | 2021-04-01 12:00:00-05
2020-04-01 17:00:00 | 2020-03-08 02:00:00 | 2020-11-01 02:00:00 | CDT | 2020-04-01 12:00:00-05
2020-12-01 17:00:00 | 2020-03-08 02:00:00 | 2020-11-01 02:00:00 | CST | 2020-12-01 11:00:00-06
(4 rows)
,
system.admin(admin)=> select '2021-04-07 11:00:00' as gmt,timezone('2021-04-07 11:00:00','GMT','America/New_York') as eastern,'America/Chicago') as central,'America/Los_Angeles') as pacific;
gmt | eastern | central | pacific
---------------------+---------------------+---------------------+---------------------
2021-04-07 11:00:00 | 2021-04-07 07:00:00 | 2021-04-07 06:00:00 | 2021-04-07 04:00:00
(1 row)
system.admin(admin)=> select '2021-03-07 11:00:00' as gmt,timezone('2021-03-07 11:00:00','America/Los_Angeles') as pacific;
gmt | eastern | central | pacific
---------------------+---------------------+---------------------+---------------------
2021-03-07 11:00:00 | 2021-03-07 06:00:00 | 2021-03-07 05:00:00 | 2021-03-07 03:00:00
(1 row)
如果我们使用如上所示的“美国/芝加哥”而不是 CDT 和 CST,它会处理夏令时。