2016-06-21 7 views
1

Ich bin in der Lage, Datum in Unix-Zeitstempel zu konvertieren. Aber ich habe ein Problem bei der Konvertierung von historischen Daten in der Datenbank in den korrekten Unix-Zeitstempel. Da Daten im Datumsformat gespeichert werden, sind für diese Daten keine Zeitzonen verfügbar. Kann ich irgendwie feststellen, ob irgendein historisches Datum in cdt oder cst ist?Konvertieren Sie historische Daten in (Datum) Typ Oracle zu Unix Zeitstempel unter Berücksichtigung der Sommerzeit

Derzeit verwende ich eine der Methoden, um Datum in Zeitstempel zu konvertieren.

create or replace function unix_time_from_date 
     (
     in_date in date 
     -- in_src_tz in varchar2 default 'America/Chicago' 
    ) 
    return integer 
    as 
    ut  integer  := 0; 
    tz  varchar2(8) := ''; 
    tz_date timestamp with time zone; 
    tz_stmt varchar2(255); 
    in_src_tz varchar2(255):='America/Chicago'; 
    begin 
tz_stmt := 'select systimestamp at time zone ''' || in_src_tz || ''' from dual'; 



    execute immediate tz_stmt into tz_date; 
    select 
     extract(timezone_abbr from tz_date) 
    into tz 
    from dual; 



    -- Get the Unix timestamp 
    select 
     (new_time(in_date, tz, 'GMT') - to_date('01-JAN-1970', 'DD-MM-YYYY')) * (86400) 
    into ut 
    from dual; 

    return ut; 
end unix_time_from_date; 

von Genommen: http://jrfom.com/2015archive/2012/02/10/oracle-and-unix-timestamps-revisited/

Da gespeicherten Objekte keine Zeitzone haben es sys Zeitzone als cdt nehmen und gibt Differenz von 1 Stunde für Daten in cst Zeitzone.

Antwort

1

Ihre Funktion extrahiert die Zeitzonenabkürzung für heute und wendet diese auf das angegebene Datum an, wobei davon ausgegangen wird, dass sich alle Daten in dieser Zone befinden. Es wird die Hälfte der Zeit das richtige Ergebnis liefern - aber nur bis zur Hälfte der Werte. (Im Winter wird die Sommerzeit falsch sein; im Sommer wird die Winterzeit falsch sein). Wenn Sie den Namen der Region anstelle der Abkürzung verwenden würden, würde das nicht funktionieren. Aber dann kannst du nicht new_time() verwenden, das sowieso nur ein paar Zonen erkennt, also musst du at time zone verwenden.

Mit Beispieldaten aus den letzten sechs Monaten (um die DST-Grenze zu überqueren; dies wird in London ausgeführt, funktioniert aber auch in Chicago, und Ihre Funktion bei der Übernahme von Chicago), können Sie sehen, was Ihre aktuelle Funktion Ihnen gibt:

with t (dt) as (
    select add_months(trunc(sysdate), -level) 
    from dual 
    connect by level <= 6 
) 
select dt dt, 
    unix_time_from_date(dt) unix_time_from_date 
from t 
order by dt; 

DT     UNIX_TIME_FROM_DATE 
------------------- ------------------- 
2015-12-21 00:00:00   1450674000 
2016-01-21 00:00:00   1453352400 
2016-02-21 00:00:00   1456030800 
2016-03-21 00:00:00   1458536400 
2016-04-21 00:00:00   1461214800 
2016-05-21 00:00:00   1463806800 

Sie können Oracle sagen, welche Zeitzonenregion das Datum darstellen soll. Wenn Sie das Datum in einen Zeitstempel umwandeln, bleibt es im Wesentlichen gleich. Wenn Sie es in einen Zeitstempel mit Tome-Zone umwandeln, wird die Zeitzone des Servers angenommen. Anschließend können Sie das mit at time zone zu UTC konvertieren und subtrahieren 1970-01-01 aus, dass die Epoche Zahl zu erhalten:

with t (dt) as (
    select add_months(trunc(sysdate), -level) 
    from dual 
    connect by level <= 6 
) 
select dt dt, 
    cast(dt as timestamp) ts, 
    cast(dt as timestamp with time zone) tstz, 
    cast(dt as timestamp with time zone) at time zone 'UTC' as utc, 
    86400 * (cast(cast(dt as timestamp with time zone) at time zone 'UTC' as date) 
    - date '1970-01-01') as epoch 
from t 
order by dt; 

DT     TS     TSTZ        UTC       EPOCH 
------------------- ------------------- --------------------------------- ----------------------- ----------- 
2015-12-21 00:00:00 2015-12-21 00:00:00 2015-12-21 00:00:00 Europe/London 2015-12-21 00:00:00 UTC 1450656000 
2016-01-21 00:00:00 2016-01-21 00:00:00 2016-01-21 00:00:00 Europe/London 2016-01-21 00:00:00 UTC 1453334400 
2016-02-21 00:00:00 2016-02-21 00:00:00 2016-02-21 00:00:00 Europe/London 2016-02-21 00:00:00 UTC 1456012800 
2016-03-21 00:00:00 2016-03-21 00:00:00 2016-03-21 00:00:00 Europe/London 2016-03-21 00:00:00 UTC 1458518400 
2016-04-21 00:00:00 2016-04-21 00:00:00 2016-04-21 00:00:00 Europe/London 2016-04-20 23:00:00 UTC 1461193200 
2016-05-21 00:00:00 2016-05-21 00:00:00 2016-05-21 00:00:00 Europe/London 2016-05-20 23:00:00 UTC 1463785200 

Als Alternative Art und Weise den UTC-äquivalent zu bekommen, immer noch auf der Server-Zeitzone, Sie können sys_extract_utc() verwenden:

with t (dt) as (
    select add_months(trunc(sysdate), -level) 
    from dual 
    connect by level <= 6 
) 
select dt dt, 
    cast(dt as timestamp) ts, 
    cast(dt as timestamp with time zone) tstz, 
    sys_extract_utc(cast(dt as timestamp)) as utc, 
    86400 * (cast(sys_extract_utc(cast(dt as timestamp with time zone)) as date) 
    - date '1970-01-01') as epoch 
from t 
order by dt; 

Oder wenn Sie die Server-Zeitzone verwenden mögen, aber man nicht stattdessen angeben, die für diese Demo sowieso etwas hilfreich:

with t (dt) as (
    select add_months(trunc(sysdate), -level) 
    from dual 
    connect by level <= 6 
) 
select dt dt, 
    cast(dt as timestamp) ts, 
    from_tz(cast(dt as timestamp), 'America/Chicago') tstz, 
    from_tz(cast(dt as timestamp), 'America/Chicago') at time zone 'UTC' as utc, 
    86400 * (cast(from_tz(cast(dt as timestamp), 'America/Chicago') at time zone 'UTC' as date) 
    - date '1970-01-01') as epoch 
from t 
order by dt; 

DT     TS     TSTZ        UTC       EPOCH 
------------------- ------------------- ----------------------------------- ----------------------- ----------- 
2015-12-21 00:00:00 2015-12-21 00:00:00 2015-12-21 00:00:00 America/Chicago 2015-12-21 06:00:00 UTC 1450677600 
2016-01-21 00:00:00 2016-01-21 00:00:00 2016-01-21 00:00:00 America/Chicago 2016-01-21 06:00:00 UTC 1453356000 
2016-02-21 00:00:00 2016-02-21 00:00:00 2016-02-21 00:00:00 America/Chicago 2016-02-21 06:00:00 UTC 1456034400 
2016-03-21 00:00:00 2016-03-21 00:00:00 2016-03-21 00:00:00 America/Chicago 2016-03-21 05:00:00 UTC 1458536400 
2016-04-21 00:00:00 2016-04-21 00:00:00 2016-04-21 00:00:00 America/Chicago 2016-04-21 05:00:00 UTC 1461214800 
2016-05-21 00:00:00 2016-05-21 00:00:00 2016-05-21 00:00:00 America/Chicago 2016-05-21 05:00:00 UTC 1463806800 

Und das mit Ihrer Funktion berechnet Epoche Vergleich:

with t (dt) as (
    select add_months(trunc(sysdate), -level) 
    from dual 
    connect by level <= 6 
) 
select dt dt, 
    unix_time_from_date(dt) unix_time_from_date, 
    86400 * (cast(from_tz(cast(dt as timestamp), 'America/Chicago') at time zone 'UTC' as date) 
    - date '1970-01-01') as epoch, 
    unix_time_from_date(dt) - 
    ( 86400 * (cast(from_tz(cast(dt as timestamp), 'America/Chicago') at time zone 'UTC' as date) 
    - date '1970-01-01')) as diff 
from t 
order by dt; 

DT     UNIX_TIME_FROM_DATE  EPOCH DIFF 
------------------- ------------------- ----------- ------ 
2015-12-21 00:00:00   1450674000 1450677600 -3600 
2016-01-21 00:00:00   1453352400 1453356000 -3600 
2016-02-21 00:00:00   1456030800 1456034400 -3600 
2016-03-21 00:00:00   1458536400 1458536400  0 
2016-04-21 00:00:00   1461214800 1461214800  0 
2016-05-21 00:00:00   1463806800 1463806800  0 

Aber Sie Zustand haben noch - und damit vielleicht annehmen - in welcher Zeitzone ursprünglich das Datum repräsentiert. Sie tun das schon in Ihrer Funktion, also glaube ich nicht, dass das ein Problem ist.

+0

Vielen Dank. Ich konnte nicht vor der Veröffentlichung der Frage bei UTC casten. Du hast das Problem gelöst. – sinner

Verwandte Themen