Oracle 从 GMT 转换为 EST 和 EDT

Oracle convert from GMT to EST and EDT

提问人:Darrell 提问时间:12/26/2022 更新时间:12/26/2022 访问量:268

问:

我使用的是 Oracle 19c。

我需要将日期从 GMT 转换为 EST 和 EDT。

我正在使用以下方法:

 1. Get the destination time zone abbreviation for the p_date variable: 

DEFINE p_date TO_DATE('03/11/2013 02:22:21', 'MM/DD/YYYY HH24:MI:SS');

SELECT TO_CHAR(FROM_TZ(CAST (&p_date AS TIMESTAMP), 'America/New_York'), 'TZD') INTO v_tzabbrev FROM DUAL; 

Where:
  p_date:  is the date to be converted.
  v_tzname:  is the time zone name, such as America/New_York
  v_tzabbrev:  is the time zone abbreviation, such as 'EDT' or "EST" based on whether the date is during Daylight Saving Time or not


2. Convert the p_date using the time zone abbreviation obtained in #1

 SELECT NEW_TIME(p_date, 'GMT', v_tzabbrev) INTO v_date FROM DUAL;

这似乎有效。但是,我认为缺陷在于它使用 GMT 日期来确定目的地时区缩写,这是不准确的。

例如,如果 UTC 中的p_date是“03/11/2013 02:22:21”,我需要将其转换为“America/New_York”,则步骤 #1 将返回“EDT”,但东部的这个日期实际上是“03/10/2013 21:22:21”,这是夏令时开始之前。因此,它实际上应该使用“EST”进行转换。

2013 年的夏令时从 3 月 10 日星期日凌晨 2 点开始。

因此,我似乎需要一种方法来获取 GMT 值并首先确定其在东部的新日期,然后根据新日期是 EDT 还是 EST 应用其他逻辑。

任何帮助都是值得赞赏的。

甲骨文 时区 GMT

评论

2赞 Alex Poole 12/26/2022
“2013 年的夏令时从 3 月 10 日星期日凌晨 2 点开始”——03/10/2013 21:22:21 是在那之后——那么为什么你认为它不应该是 EDT?
0赞 Andrew 12/31/2022
顺便说一句,“EST”和“EDT”不是通用定义的

答:

1赞 Wernfried Domscheit 12/26/2022 #1

您可以直接定义为 UTC 时间:p_date

DEFINE p_date TO_TIMESTAMP_TZ('03/11/2013 02:22:21 UTC', 'MM/DD/YYYY HH24:MI:SS TZR');

SELECT TO_CHAR((&p_date AT TIME ZONE 'America/New_York'), 'TZD') 
INTO v_tzabbrev 
FROM DUAL; 

或者在声明中:

DEFINE p_date TO_DATE('03/11/2013 02:22:21', 'MM/DD/YYYY HH24:MI:SS');

SELECT TO_CHAR((FROM_TZ(CAST(&p_date AS TIMESTAMP), 'UTC') AT TIME ZONE 'America/New_York'), 'TZD') 
INTO v_tzabbrev 
FROM DUAL; 

另一种可能性是隐式使用,尽管我不建议这样做:SESSIONTIMEZONE

DEFINE p_date TO_DATE('03/11/2013 02:22:21', 'MM/DD/YYYY HH24:MI:SS');
ALTER SESSION SET TIME ZONE = 'UTC';

SELECT TO_CHAR((CAST(&p_date AS TIMESTAMP WITH TIME ZONE) AT TIME ZONE 'America/New_York'), 'TZD') 
INTO v_tzabbrev 
FROM DUAL; 

评论

0赞 Darrell 12/26/2022
谢谢。但是,您的第一个示例也返回 EDT。东部日期实际上是“03/10/2013 21:22:21”,即美国东部时间。我的 SESSIONTIMEZONE 已经是 UTC。因此,第二个示例产生相同的结果。
0赞 Alex Poole 12/26/2022 #2

“2013 年的夏令时从 3 月 10 日星期日凌晨 2 点开始。”

...这是正确的,您可以看到 UTC 等效日期/时间发生的情况如下:

-- get New York DST start time as UTC
with cte (ts) as (
  select timestamp '2013-03-10 01:59:59 America/New_York' from dual
  union all
  select timestamp '2013-03-10 03:00:00 America/New_York' from dual
)
select ts, to_char(ts, 'TZD') as tzd, ts at time zone 'UTC' as ts_utc
from cte
TS型 TZD公司 TS_UTC
2013-03-10 01:59:59 美国/NEW_YORK 2013-03-10 06:59:59 UTC
2013-03-10 03:01:00 AMERICA/NEW_YORK 美国东部时间 2013-03-10 07:00:00 UTC

但东部的这个日期实际上是“03/10/2013 21:22:21”,这是夏令时开始之前。

不,不是,它是在 DST 开始之后

因此,它实际上应该使用“EST”进行转换。

不,它不应该。恐怕你问题的前提是错误的。

您正在进行的转换是获得正确的结果:

-- get UTC timestamp as New York
with cte (ts) as (
  select timestamp '2013-03-11 02:22:21 UTC' from dual
)
select ts as ts_utc, ts at time zone 'America/New_YORK' as ts, to_char(ts at time zone 'America/New_York', 'TZD') as tzd
from cte
TS_UTC TS型 TZD公司
2013-03-11 02:22:21 UTC 2013-03-10 22:22:21 美国/NEW_YORK 美国东部时间

小提琴

2013-03-11 02:22:21 UTC 是在 2013-03-10 01:59:59 America/New_York 之后,因为它是 UTC 的第二天,以及纽约 DST 切换发生后的 19 小时。换言之,2013-03-11 02:22:21 UTC 是 2012-03-10 07:00:00 UTC 之后的 19 小时,这与上述第一个查询的 EDT 开始时间等效。

您似乎将 UTC 值中的日期与当年在美国应用 DST 的日期混淆了。


因为 NEW_TIME() 函数是有限的,所以我更愿意使用 和 ,正如 Wernfried 所示。FROM_TZAT TIME ZONE

评论

0赞 Darrell 12/26/2022
不好意思。你是对的。我怀疑我只需要多研究一下。甚至以下用例似乎也有效。如果p_date是“2013-03-10 01:59:59 America/New_York”,就在夏令时之前,UTC 等效于“2013-03-10 06:59:59 UTC”,该怎么办?然后 SELECT TO_CHAR((FROM_TZ(CAST(&p_date AS TIMESTAMP), 'UTC') AT TIME ZONE 'America/New_York'), 'TZD') FROM DUAL 返回 'EST',这是正确的。所以,尽管我怀疑,但我的逻辑似乎是正确的。因此,感谢您的及时反馈。