sql >> Base de Datos >  >> RDS >> Oracle

Convierta la fecha y hora local (con zona horaria) en una marca de tiempo de Unix en Oracle

Puede convertir su marca de tiempo con zona horaria a UTC y luego restar la época de eso:

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

lo que le da un tipo de datos de intervalo:

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

Luego puede extraer los elementos de eso y multiplicar cada elemento por un factor apropiado para convertirlo a milisegundos (es decir, para días, 60 * 60 * 24 * 1000); y luego sumarlos:

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<>fiddle

Esto también conserva milisegundos, si la marca de tiempo inicial los tiene (esto se convierte de un tiempo 'Unix' mientras los conserva):

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

luego para volver a convertir:

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<>violín

Si su marca de tiempo inicial tiene una precisión mayor que esa, entonces deberá truncar (o redondear/piso/techo/emisión) para evitar tener un resultado no entero; esta versión solo trunca la parte de milisegundos extraída:

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

Sin ese truncamiento (o equivalente), terminaría con 1539961967123.456789 .

Me había olvidado de la discrepancia de los segundos bisiestos; si necesita/quiere manejar eso, vea esta respuesta .