Oracle
 sql >> Base de données >  >> RDS >> Oracle

Convertir la date et l'heure locales (avec fuseau horaire) en un horodatage Unix dans Oracle

Vous pouvez convertir votre horodatage avec fuseau horaire en UTC, puis en soustraire l'époque :

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

qui vous donne un type de données d'intervalle :

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

Vous pouvez ensuite en extraire les éléments et multiplier chaque élément par un facteur approprié pour le convertir en millisecondes (c'est-à-dire pour les jours, 60*60*24*1000) ; puis additionnez-les :

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

Cela préserve également les millisecondes, si l'horodatage de départ en a (cela convertit à partir d'un temps 'Unix' tout en les préservant) :

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

puis pour reconvertir :

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

Si votre horodatage de départ a une plus grande précision que cela, vous devrez tronquer (ou arrondir/plancher/plafond/cast) pour éviter d'avoir un résultat non entier ; cette version tronque simplement la partie extraite en millisecondes :

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

Sans cette troncature (ou équivalent), vous vous retrouveriez avec 1539961967123.456789 .

J'avais oublié l'écart des secondes intercalaires ; si vous avez besoin/voulez gérer cela, voir cette réponse .