Home > Net >  Oracle convert from GMT to EST and EDT
Oracle convert from GMT to EST and EDT

Time:12-26

I am using Oracle 19c.

I need to convert dates from GMT to EST and EDT.

I am using the following approach:

 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;

This seems to work. But, I believe the flaw is that it is using the GMT date to determine the destination time zone abbreviation, which is inaccurate.

For example, if p_date, in UTC, is '03/11/2013 02:22:21' and I need to convert it to 'America/New_York', Step #1 would return 'EDT', but this date in Eastern was actually "03/10/2013 21:22:21", which was before Daylight Saving started. So, it should actually be converted using "EST".

Daylight saving time in '2013 began at 2 a.m. on Sunday, March 10.

So, it seems that I need a way to take the GMT value and determine its new date in Eastern first, then apply additional logic based on whether that new date is EDT or EST.

Any assistance is appreciated.

CodePudding user response:

You can define p_date directly as UTC time:

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; 

Or in the statement:

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; 

Another possibility is to use SESSIONTIMEZONE implicitly, although I don't recommend this:

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; 

CodePudding user response:

"Daylight saving time in '2013 began at 2 a.m. on Sunday, March 10."

... which is correct, and you can see that happening with the UTC equivalent date/time as:

-- 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 AMERICA/NEW_YORK EST 2013-03-10 06:59:59 UTC
2013-03-10 03:00:00 AMERICA/NEW_YORK EDT 2013-03-10 07:00:00 UTC

but this date in Eastern was actually "03/10/2013 21:22:21", which was before Daylight Saving started.

No, it isn't, it's after DST started.

So, it should actually be converted using "EST".

No, it shouldn't. I'm afraid the premise of your question is wrong.

The conversion you are doing is getting the correct result:

-- 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 AMERICA/NEW_YORK EDT

fiddle

2013-03-11 02:22:21 UTC is after 2013-03-10 01:59:59 America/New_York, as it is the following day in UTC, and 19 hours after the New York DST switch occurred. In other words, 2013-03-11 02:22:21 UTC is 19 hours after 2012-03-10 07:00:00 UTC, which is the UTC equivalent of the EDT start-time from the first query above.

You seem to be confusing the date in your UTC value with the date that DST was applied in the USA that year.


Because the NEW_TIME() function is limited, I would prefer to use FROM_TZ and AT TIME ZONE, as Wernfried showed.

  • Related