Oracle
 sql >> Database >  >> RDS >> Oracle

Converti data e ora locale (con fuso orario) in un timestamp Unix in Oracle

Puoi convertire il tuo timestamp con fuso orario in UTC, quindi sottrarre l'epoca da quello:

select timestamp '2018-10-19 09:12:47.0 AMERICA/DENVER'
  - timestamp '1970-01-01 00:00:00.0 UTC' as diff
from dual;

che ti dà un tipo di dati di intervallo:

DIFF                  
----------------------
+17823 15:12:47.000000

Puoi quindi estrarre gli elementi da quello e moltiplicare ogni elemento per un fattore appropriato per convertirlo in millisecondi (cioè per giorni, 60*60*24*1000); e poi aggiungili insieme:

select extract(day from diff) * 86400000
  + extract(hour from diff) * 3600000
  + extract(minute from diff) * 60000
  + extract(second from diff) * 1000 as unixtime
from (
  select timestamp '2018-10-19 09:12:47.0 AMERICA/DENVER'
    - timestamp '1970-01-01 00:00:00.0 UTC' as diff
  from dual
);

            UNIXTIME
--------------------
       1539961967000

db<>violino

Ciò conserva anche i millisecondi, se il timestamp iniziale li ha (questo converte da un'ora "Unix" preservandoli):

select (timestamp '1970-01-01 00:00:00.0 UTC' + (1539961967567 * interval '0.001' second))
  at time zone 'America/Denver' as denver_time
from dual;

DENVER_TIME                                 
--------------------------------------------
2018-10-19 09:12:47.567000000 AMERICA/DENVER

quindi per riconvertire:

select extract(day from diff) * 86400000
  + extract(hour from diff) * 3600000
  + extract(minute from diff) * 60000
  + extract(second from diff) * 1000 as unixtime
from (
  select timestamp '2018-10-19 09:12:47.567 AMERICA/DENVER'
    - timestamp '1970-01-01 00:00:00.0 UTC' as diff
  from dual
);

            UNIXTIME
--------------------
       1539961967567

db<>violino

Se il tuo timestamp iniziale ha una precisione maggiore di quella, dovrai troncare (o round/floor/ceil/cast) per evitare di avere un risultato non intero; questa versione tronca solo la parte di millisecondi estratta:

select diff,
  extract(day from diff) * 86400000
  + extract(hour from diff) * 3600000
  + extract(minute from diff) * 60000
  + trunc(extract(second from diff) * 1000) as unixtime
from (
  select timestamp '2018-10-19 09:12:47.123456789 AMERICA/DENVER'
    - timestamp '1970-01-01 00:00:00.0 UTC' as diff
  from dual
);

DIFF                                  UNIXTIME
------------------------- --------------------
+17823 15:12:47.123456789        1539961967123

Senza quel troncamento (o equivalente) finiresti con 1539961967123.456789 .

Mi ero dimenticato della discrepanza dei secondi intercalari; se hai bisogno/vuoi gestirlo, vedi questa risposta .