Home » SQL & PL/SQL » SQL & PL/SQL » Wrong result in trying to find offset change time (Oracle 11.2.0.3.0 on OEL 5.7 to Oracle 11.2.0.1.0 OEL 5.7)
Wrong result in trying to find offset change time [message #609254] Tue, 04 March 2014 15:50 Go to next message
Andrey_R
Messages: 441
Registered: January 2012
Location: Israel
Senior Member
Hi all,

I am trying to write a code that will

*receives time zone name
*checks if there is an offset change in the next 300 hours

*if no => will print/return the UTC date as it will be in 300 hours from now
*if yes => will print/return the LOCAL date as it will be a second before the change kicks in

In one of my versions I run the following code:

SQL> declare
  2    p_tzname varchar2(50) := 'America/Argentina/Cordoba';
  3    p_hours  number := 300;
  4    --
  5    v_offset_doesnt_change   number(1) := 1;
  6    v_halfhours_offset_check number(4, 1) := 0.5;
  7    --
  8    v_local_time        date;
  9    utc_time            date;
 10    v_curr_offset       number(10, 5);
 11    v_offset_in_300_hrs number(10, 5);
 12    result              varchar2(100);
 13  begin
 14    --initialize utc time:
 15    select cast(sys_extract_utc(systimestamp) as date)
 16      into utc_time
 17      from dual;
 18    dbms_output.put_line(utc_time);
 19    --initialize offset from UTC at that timezone:
 20    execute immediate 'select convert_alpha_time_to_offset(to_char(from_tz(cast(' ||
 21                      'to_date(''' || utc_time || ''')' || ' as timestamp),' || '''' ||
 22                      p_tzname || '''' || '),''tzh:tzm'')) from dual'
 23      into v_curr_offset;
 24    --initialize offset from UTC at that timezone in x hours from now:
 25    execute immediate 'select convert_alpha_time_to_offset(to_char(from_tz(cast(' ||
 26                      'to_date(''' || utc_time || ''')+' || p_hours / 24 ||
 27                      ' as timestamp),' || '''' || p_tzname || '''' ||
 28                      '),''tzh:tzm'')) from dual'
 29      into v_offset_in_300_hrs;
 30    --initialize localtime:
 31    v_local_time := utc_time + v_curr_offset;
 32    --
 33    --output the vars, so far:
 34    dbms_output.put_line('utc_time is: ' || utc_time);
 35    dbms_output.put_line('v_curr_offset is: ' || v_curr_offset || ' (' ||
 36                         round(v_curr_offset * 24) || ' hours)');
 37    dbms_output.put_line('v_offset_in_300_hrs is: ' || v_offset_in_300_hrs || ' (' ||
 38                         round(v_offset_in_300_hrs * 24) || ' hours)');
 39    dbms_output.put_line('v_local_time is: ' || v_local_time);
 40    --
 41    --check if current offset, and offset in "p_hours" from now will be the same:
 42    if v_curr_offset = v_offset_in_300_hrs then
 43      --if offset doesn't change - return the UTC time in 300 hours from now, trunced by bits of 30 minutes:

 44      --return
 45      dbms_output.put_line(utc_time + p_hours / 24 -
 46                           (mod(to_char(utc_time, 'mi'), 30) / 1440 +
 47                           mod(to_char(utc_time, 'ss'), 60) / (1440 * 60)));
 48    else
 49      --else , will check what will be the next time when time will change:
 50      begin
 51        --i1
 52        while v_offset_doesnt_change = 1 loop
 53          --check, by 0.5 hour increments, when is the offset changing:
 54          execute immediate 'select count(*) from dual where
 55     convert_alpha_time_to_offset(to_char(from_tz(cast(' ||
 56                            'to_date(''' || utc_time || ''')+' ||
 57                            v_halfhours_offset_check || '/' || 24 ||
 58                            ' as timestamp),' || '''' || p_tzname || '''' ||
 59                            '),''tzh:tzm'')) =
 60     (select convert_alpha_time_to_offset(to_char(from_tz(cast(' ||
 61                            'to_date(''' || utc_time || ''')' ||
 62                            ' as timestamp),' || '''' || p_tzname || '''' ||
 63                            '),''tzh:tzm'')) from dual)'
 64            into v_offset_doesnt_change;
 65
 66          v_halfhours_offset_check := v_halfhours_offset_check + 0.5;
 67          --
 68        --   dbms_output.put_line('v_offset_doesnt_change is: '||v_offset_doesnt_change);
 69        --    v_offset_doesnt_change := 0;
 70        end loop;
 71        result := v_local_time + (v_halfhours_offset_check - 0.5) / 24 -
 72                  (mod(to_char(v_local_time, 'mi'), 30) / 1440 +
 73                  mod(to_char(v_local_time, 'ss'), 60) / (1440 * 60)) -
 74                  0.00001;
 75        dbms_output.put_line('Local time , a second before offset changes is: '||result);
 76      end; --i1
 77    end if;
 78  end;
 79  /
04.03.2014 21:37:58
utc_time is: 04.03.2014 21:37:58
v_curr_offset is: -.08333 (-2 hours)
v_offset_in_300_hrs is: -.125 (-3 hours)
v_local_time is: 04.03.2014 19:37:58
Local time , a second before offset changes is: 15.03.2014 20:59:59

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.43


Unfortunately,
This does not fit to the results of the query I use to check myself about "predicting" offset changes:

SQL> set pages 200 lines 200
SQL> col offset_BEFORE_shift for a30
SQL> col offset_AFTER_estimated_shift for a30
SQL> col offset_AFTER_REAL_shift for a30
SQL> select to_char(from_tz(cast(to_date('2013-03-15 20:59:59',
  2                                      'YYYY-MM-DD HH24:MI:SS') as timestamp),
  3                         'UTC') AT TIME ZONE 'America/Argentina/Cordoba',
  4                 'tzh:tzm') "offset_BEFORE_shift",
  5         to_char(from_tz(cast(to_date('2013-03-15 22:59:59',
  6                                      'YYYY-MM-DD HH24:MI:SS') as timestamp),
  7                         'UTC') AT TIME ZONE 'America/Argentina/Cordoba',
  8                 'tzh:tzm') "offset_AFTER_estimated_shift",
  9         to_char(from_tz(cast(to_date('2013-03-17 02:00:00',
 10                                      'YYYY-MM-DD HH24:MI:SS') as timestamp),
 11                         'UTC') AT TIME ZONE 'America/Argentina/Cordoba',
 12                 'tzh:tzm') "offset_AFTER_REAL_shift"
 13    from dual;

offset_BEFORE_shift            offset_AFTER_estimated_shift   offset_AFTER_REAL_shift
------------------------------ ------------------------------ ------------------------------
-02:00                         -02:00                         -03:00

Elapsed: 00:00:00.00


I am clearly doing something wrong somewhere.. for most of the time zones in v$timezone_names I am getting it right,
But with some 5% I have this inaccuracy, and can't understand why Sad

Thanks in advance.

Regards,
Andrey
Re: Wrong result in trying to find offset change time [message #609256 is a reply to message #609254] Tue, 04 March 2014 20:23 Go to previous messageGo to next message
msol25
Messages: 396
Registered: June 2011
Senior Member
hi,

Please can u tell me that what convert_alpha_time_to_offset at this place?

[Updated on: Tue, 04 March 2014 20:24]

Report message to a moderator

Re: Wrong result in trying to find offset change time [message #609274 is a reply to message #609256] Wed, 05 March 2014 01:17 Go to previous messageGo to next message
Andrey_R
Messages: 441
Registered: January 2012
Location: Israel
Senior Member
msol25 wrote on Wed, 05 March 2014 04:23
hi,

Please can u tell me that what convert_alpha_time_to_offset at this place?



Sure, it's a function that converts an offset that you get by Oracle functions (from_tz, to_char) in format 'tzh:tzm', to a numerical value that you can use for math:
Here's the code:

CREATE OR REPLACE FUNCTION "CONVERT_ALPHA_TIME_TO_OFFSET"
    (pTheTime varchar2)
return number
deterministic
parallel_enable
is
   convertedTime number;
   theTime varchar2(8);
   multiplier number default 1;
begin
   if substr(trim(pTheTime),1,1) in ('+','-') then
     theTime := substr(trim(replace(pTheTime,':',''))||'000000',2,6);
     if substr(trim(pTheTime),1,1)='-' then
       multiplier := -1;
     end if;
   else
     theTime := substr(trim(replace(pTheTime,':',''))||'000000',1,6);
   end if;
   begin
     convertedTime := (to_date(lpad(trim(least(235959,theTime)),6,'0'),'HH24MISS') - round(to_date('01','HH')));
   exception
     when others then
       dbms_output.put_line('Invalid Time:'||pTheTime);
   end;
   return (convertedTime*multiplier);
end CONVERT_ALPHA_TIME_TO_OFFSET;

[Updated on: Wed, 05 March 2014 01:18]

Report message to a moderator

Re: Wrong result in trying to find offset change time [message #609276 is a reply to message #609274] Wed, 05 March 2014 01:28 Go to previous messageGo to next message
Andrey_R
Messages: 441
Registered: January 2012
Location: Israel
Senior Member
Usage is like this:

select convert_alpha_time_to_offset( to_char(FROM_TZ( sys_extract_utc(systimestamp),  'Europe/Moscow' ),'tzh:tzm')) from dual
Re: Wrong result in trying to find offset change time [message #609297 is a reply to message #609276] Wed, 05 March 2014 04:01 Go to previous message
Andrey_R
Messages: 441
Registered: January 2012
Location: Israel
Senior Member
Hi all,
I have found my mistake, and very unfortunately, it is mostly semantic:

1.
When I checked my findings with the SQL:

SQL> set pages 200 lines 200
SQL> col offset_BEFORE_shift for a30
SQL> col offset_AFTER_estimated_shift for a30
SQL> col offset_AFTER_REAL_shift for a30
SQL> select to_char(from_tz(cast(to_date('2013-03-15 20:59:59',
  2                                      'YYYY-MM-DD HH24:MI:SS') as timestamp),
  3                         'UTC') AT TIME ZONE 'America/Argentina/Cordoba',
  4                 'tzh:tzm') "offset_BEFORE_shift",
  5         to_char(from_tz(cast(to_date('2013-03-15 22:59:59',
  6                                      'YYYY-MM-DD HH24:MI:SS') as timestamp),
  7                         'UTC') AT TIME ZONE 'America/Argentina/Cordoba',
  8                 'tzh:tzm') "offset_AFTER_estimated_shift",
  9         to_char(from_tz(cast(to_date('2013-03-17 02:00:00',
 10                                      'YYYY-MM-DD HH24:MI:SS') as timestamp),
 11                         'UTC') AT TIME ZONE 'America/Argentina/Cordoba',
 12                 'tzh:tzm') "offset_AFTER_REAL_shift"
 13    from dual;

offset_BEFORE_shift            offset_AFTER_estimated_shift   offset_AFTER_REAL_shift
------------------------------ ------------------------------ ------------------------------
-02:00                         -02:00                         -03:00

Elapsed: 00:00:00.00


I used the year 2013, whereas in my PL/SQL I was checking my next offset change, and we are in the year 2014 now...
(please ignore the fact that Goodle says Argentina/Cordoba has no offset change this year, my timezone file is old and "doesn't know" it).

2. In my PL/SQL code , I wasn't addressing the UTC timezone and it's difference from the specified timezone with the AT TIME ZONE clause.
I am doing it in my SQL so that's a good reason for building the syntax in a similar way

3. When I am checking with my SQL - I need to put the UTC dates and times in the quoted strings, and not the local ones. So from the result of the PL/SQL block I need to subtract the offset and put the result into the quoted string.



Thank you for your attempt and will to assist!

Best Regards,
Andrey R.
Previous Topic: cursor_sharing force 11g r2
Next Topic: SDO_GTYPE count and group by based on tables in all_tab_cols?
Goto Forum:
  


Current Time: Fri Apr 26 14:10:44 CDT 2024