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.
Vielen Dank. Ich konnte nicht vor der Veröffentlichung der Frage bei UTC casten. Du hast das Problem gelöst. – sinner