提问人:Darrell 提问时间:12/26/2022 更新时间:12/26/2022 访问量:268
Oracle 从 GMT 转换为 EST 和 EDT
Oracle convert from GMT to EST and EDT
问:
我使用的是 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 应用其他逻辑。
任何帮助都是值得赞赏的。
答:
您可以直接定义为 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;
评论
“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_TZ
AT TIME ZONE
评论