2016-04-11 12 views
0

Meine Anforderung hier ist, Zeit in GMT/UTC von einer Datumsart Spalte zu bekommen. Aber wenn ich Cast verwende, um das Datum auf den Zeitstempel zu setzen, verwendet es die Zeitzone USA/Pazifik als Referenz, obwohl die Zeitzone der Sitzung auf GMT eingestellt ist. Wenn ich also nicht from__tz benutze, sehe ich kein gewünschtes Ergebnis. Gibt es eine andere Zeitzone in Oracle SQL, die ich ändern muss, um GMT immer als Referenz zu verwenden?Oracle sql Zeitzone Problem

alter session set time_zone='+00:00'; 
select sessiontimezone from dual; 
select current_timestamp from dual; 
select sys_extract_utc(cast (sysdate as timestamp)) from dual; 
select sys_extract_utc(from_tz(cast (sysdate as timestamp), '-07:00')) from dual; 
select sys_extract_utc(current_timestamp) from dual; 


Session altered. 


SESSIONTIMEZONE 
--------------------------------------------------------------------------- 
+00:00 


CURRENT_TIMESTAMP 
--------------------------------------------------------------------------- 
11-APR-16 08.46.42.292173 AM +00:00 


SYS_EXTRACT_UTC(CAST(SYSDATEASTIMESTAMP)) 
--------------------------------------------------------------------------- 
11-APR-16 01.46.42.000000 AM 

SYS_EXTRACT_UTC(FROM_TZ(CAST(SYSDATEASTIMESTAMP),'-07:00')) 
--------------------------------------------------------------------------- 
11-APR-16 08.46.42.000000 AM 


SYS_EXTRACT_UTC(CURRENT_TIMESTAMP) 
--------------------------------------------------------------------------- 
11-APR-16 08.46.42.295310 AM 

Die Tabelle der Aufgaben enthält eine Datumsspalte namens task_started. Ich suche nach UTC-Zeit von diesem Datumsfeld. Als Teil davon habe ich versucht, die Zeitzone der Sitzung in GMT zu ändern, während ich die Daten einfüge, so dass ich sie einfach in den Zeitstempel zurückwerfen kann, der nicht funktioniert.

select task_started from tasks where rownum <2; 

TASK_STAR 
--------- 
10-APR-16 

desc tasks; 
Name          Null? Type 
----------------------------------------- -------- ---------------------------- 
... 
TASK_STARTED          DATE 
... 
+0

Können Sie ein Beispiel für ein gespeichertes Datum (mit Zeitangabe) und die erwartete Ausgabe angeben? In welcher Zeitzone steht das Datum/die Uhrzeit in dieser Spalte, und woher weißt du das? Gibt es eine weitere Spalte, in der die Zeitzone gespeichert ist, oder ist anzunehmen, dass eine Konvertierung erforderlich ist? –

+0

@AlexPoole In meiner Tabelle ist nur das Datum gespeichert, daher werfe ich das auf den Zeitstempel zurück. Ich gehe davon aus, dass das Datum/die Uhrzeit, die in der Tabelle gespeichert werden, die Zeitzone der Sitzung verwenden sollte, die GMT ist, da ich die Zeitzone der Sitzung geändert habe. Da die Cast-Funktion die Zeit in den USA/Pazifik zurückgibt, bin ich verwirrt. –

+0

Eine Datumsspalte hat keine Zeitzone (hat aber immer eine Zeit, selbst wenn Ihre Abfrage/Ihr Client dies nicht anzeigt). Wenn Sie als einfacher Zeitstempel casten, bleibt die Zeit gleich, aber es werden immer noch keine Zeitzoneninformationen angezeigt.Bei Ihrer Frage geht es darum, das Datum/die Uhrzeit in UTC zu konvertieren, was bedeutet, dass es in einer bestimmten Zone gespeichert oder bereitgestellt wird. Z.B. Wenn das Datum ursprünglich mithilfe von sysdate eingefügt wurde, was die Serverzeitzone impliziert, und Sie möchten, dass das UTC dem entspricht. Bitte fügen Sie Daten und Ausgaben hinzu, da nicht klar ist, was Sie wirklich benötigen. –

Antwort

0

Dies ist eine Demo eingeführt unter Verwendung von Daten sysdate auf einem System auf Londoner Zeit verwendet wird, so aktuell BST (+01: 00). Der Unterschied ist kleiner als an der Westküste, aber es gelten dieselben Dinge.

Tisch Imitieren, können Sie sehen, dass die Sitzung Zeitzone keine Auswirkung auf den eingefügten Wert hat seit sysdate den Datenbankserver Zeit verwendet, nicht die Sitzung (Client) Zeit (as explained here):

alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'; 
alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS.FF3'; 
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF3 TZH:TZM'; 

create table tasks (id number, task_started date); 

alter session set time_zone='America/Los_Angeles'; 

insert into tasks (id, task_started) values (1, sysdate); 

select task_started, cast(task_started as timestamp) as ts 
from tasks where rownum < 2; 

TASK_STARTED  TS      
------------------- ----------------------- 
2016-04-11 11:55:59 2016-04-11 11:55:59.000 

alter session set time_zone = 'UTC'; 

select task_started, cast(task_started as timestamp) as ts 
from tasks where rownum < 2; 

TASK_STARTED  TS      
------------------- ----------------------- 
2016-04-11 11:55:59 2016-04-11 11:55:59.000 

So das ist die BST-Zeit in beiden Fällen. Es gibt keine Sitzungs- oder Datenbankeinstellung, die Ihnen automatisch ein Datum (oder einen Zeitstempel ohne Zeitzone) anzeigt, das in eine bestimmte Zeitzone konvertiert wird. Die Datenbank weiß nicht, was das gespeicherte Datum/die Uhrzeit darstellt, wenn Sie es nicht angeben. Sie wissen nicht, ob Sie sysdate, current_date oder ein Datumsliteral verwenden. An dem Punkt, an dem die Daten in die Tabelle eingefügt werden, hat sie überhaupt keine Zeitzoneninformationen.

Um die UTC-Entsprechung zu erhalten, müssen Sie from_tz verwenden, um zu deklarieren, dass der gespeicherte Wert eine bestimmte Zeitzone darstellt; dann können Sie at time zone verwenden (die die Zeitzoneninformation behält) oder sys_extract_utc (das nicht tut), um es umzuwandeln; und gegebenenfalls zu einem Zeitpunkt zurückgeworfen:

select from_tz(cast(task_started as timestamp), 'Europe/London') as db_tstz, 
    from_tz(cast(task_started as timestamp), 'Europe/London') at time zone 'UTC' as utc_tstz, 
    sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as utc_ts, 
    cast(sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as date) as utc_date 
from tasks where rownum < 2; 

DB_TSTZ      UTC_TSTZ      UTC_TS     UTC_DATE   
------------------------------ ------------------------------ ----------------------- ------------------- 
2016-04-11 11:55:59.000 +01:00 2016-04-11 10:55:59.000 +00:00 2016-04-11 10:55:59.000 2016-04-11 10:55:59 

ich die Zeitzone Region Namen verwendet haben, so ist es Pflege der Sommerzeit für mich nimmt; Sie könnten dbtimezone verwenden, aber das würde immer -08: 00 verwenden, und wie Sie in der Frage gezeigt haben, müssen Sie im Moment -07: 00 verwenden. Und Sie könnten sessiontimezone verwenden, aber dann müssen Sie daran denken, das richtig einzustellen. Offensichtlich würden Sie in Ihrem Fall Ihre lokale Region verwenden, z. Amerika/Los_Angeles statt Europa/London.

Und aus, dass Sie die Zeit bekommen können über ein Intervall, durch den Vergleich Zeitstempel oder einfacher aus dem Vergleich Daten:

select sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) 
    - timestamp '1970-01-01 00:00:00' as diff_interval, 
    cast(sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as date) 
    - date '1970-01-01' as diff_days, 
    86400 * 
    (cast(sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as date) 
     - date '1970-01-01') as epoch 
from tasks where rownum < 2; 

DIFF_INTERVAL DIFF_DAYS  EPOCH 
---------------- --------- ----------- 
16902 10:55:59.0 16902.46 1460372159 

Wenn Sie 1460372159 in einen Online-Konverter setzen (es gibt viele) wird es zeigt die UTC Zeit.