web-dev-qa-db-fra.com

Obtenir des secondes entre deux horodatages Oracle

Tom Kyte suggère d'utiliser EXTRACT pour faire la différence:

extract( day from (x-y) )*24*60*60+
extract( hour from (x-y) )*60*60+
...

Cela semble plus difficile à lire et plus lent que cela, par exemple:

( CAST( x AS DATE ) - CAST( y AS DATE ) ) * 86400

Alors, quelle est la façon d'obtenir la différence entre deux horodatages en quelques secondes? Merci!

18
Peter Lang

"Meilleures pratiques"

Quoi que vous fassiez, enveloppez-le dans une fonction, par ex. seconds_between (from_date, to_date) - peu importe comment il le fait (choisissez la méthode la plus efficace) - alors ce que votre code fait est parfaitement évident.

Performance

J'ai testé les deux méthodes sur 11gR1 sur mon ordinateur portable (WinXP) avec le cas de test ci-dessous. Il semble que l'option CAST soit la plus rapide. (t1 est la ligne de base, t2 a utilisé la méthode extract, t3 a utilisé la méthode cast)

t1 (nothing) 3
t2 (extract) 338
t3 (cast)    101

t1 (nothing) 3
t2 (extract) 336
t3 (cast)    100

Script de test

declare
 x TIMESTAMP := SYSTIMESTAMP;
 y TIMESTAMP := TRUNC(SYSDATE);
 n PLS_INTEGER;
 lc CONSTANT PLS_INTEGER := 1000000;
 t1 PLS_INTEGER;
 t2 PLS_INTEGER;
 t3 PLS_INTEGER;
begin
 t1 := DBMS_UTILITY.get_time;
 for i in 1..lc loop
  n := i;
 end loop;
 t1 := DBMS_UTILITY.get_time - t1;
 t2 := DBMS_UTILITY.get_time;
 for i in 1..lc loop
  n := extract(day from (x-y))*24*60*60
     + extract(hour from (x-y))*60*60
     + extract(minute from (x-y))*60
     + extract(second from (x-y));
 end loop;
 t2 := DBMS_UTILITY.get_time - t2;
 t3 := DBMS_UTILITY.get_time;
 for i in 1..lc loop
  n := ( CAST( x AS DATE ) - CAST( y AS DATE ) ) * 86400;
 end loop;
 t3 := DBMS_UTILITY.get_time - t3;
 dbms_output.put_line('t1 (nothing) ' || t1);
 dbms_output.put_line('t2 (extract) ' || t2);
 dbms_output.put_line('t3 (cast)    ' || t3);
end;
17
Jeffrey Kemp

Alternative:
J'ai trouvé que cela fonctionnait aussi pour obtenir la différence en quelques secondes, y compris les millisecondes.
C'est même enregistrer pour les fuseaux horaires avec "heure d'été" alors que la méthode d'extraction aurait un problème. Malheureusement, la différence entre t1 et t2 est limitée pour que le résultat soit correct. La diffusion d'horodatages au format de date n'est pas une option car les fractions de secondes sont perdues.

select (sysdate + (t2 - t1)*1000 - sysdate) * 86.4 from 
(select  
    to_timestamp('2014-03-30 01:00:10.111','YYYY-MM-DD HH24:MI:SS.FF') at time zone 'MET' t1, 
    to_timestamp('2014-03-30 03:00:10.112','YYYY-MM-DD HH24:MI:SS.FF') at time zone 'MET' t2 
 from dual);
9
user3820019

J'ai toujours utilisé la deuxième façon, c'est-à-dire comparer les DATES (qui vous donne le nombre de jours de différence, avec une partie fractionnaire), et la multiplier par le facteur que vous souhaitez vous donner le nombre d'heures, de minutes, de secondes ou autre.

Je pense que c'est bon et facile à lire.

3
Adrian Smith

Personnellement, je trouve:

extract(day from (x-y))*24*60*60 + ... + extract(second from (x-y))

plus clair dans son but que ...

( CAST( x AS DATE ) - CAST( y AS DATE ) ) * 86400

pour obtenir la différence en quelques secondes.

La méthode de Tom prend quelques touches de plus, mais l'intention est claire.

1
Nick Pierpoint

pour une utilisation rapide et facile:

extract( day from(t2 - t1)*24*60*60)

Exemple:

with dates as (
   select
        to_timestamp('2019-06-18 22:50:00', 'yyyy-mm-dd hh24:mi:ss') t1
      , to_timestamp('2019-06-19 00:00:38', 'yyyy-mm-dd hh24:mi:ss') t2
   from dual
)
select
    extract( day from(t2 - t1)*24*60*60) diff_in_seconds
from dates
;

Sortie:

DIFF_IN_SECONDS
---------------
            638
0
user3801158