web-dev-qa-db-fra.com

Comment soustraire 2 dates dans Oracle pour obtenir le résultat en heures et minutes

Je veux soustraire 2 dates et représenter le résultat en heures et minutes en une décimale.

J'ai le tableau suivant et je le fais de cette façon mais le résultat n'est pas comme souhaité.

Il y a une légère variation, je suis sûr que c'est de l'arithmétique simple mais je ne comprends pas bien.

select start_time, end_time, (end_time-start_time)*24 from 
come_leav;    
 
 START_TIME END_TIME (END_TIME-START_TIME) * 24 
 ------------------- ------- ------------ ------------------------ 
 21-06-2011 14:00: 00 21-06-2011 16:55:00 2.9166667 
 21-06-2011 07:00:00 21-06-2011 16:50:00 9.8333333 
 21-06-2011 07: 20:00 21-06-2011 16:30:00 9.1666667 
 

Je veux le résultat (end_time-start_time) comme ci-dessous.

 16: 55-14: 00 = 2,55 
 16: 50-07: 00 = 9,5 
 16: 30-7: 20 = 9,1 et ainsi de suite. 

Comment puis je faire ça?

9
Macky
SQL> edit
Wrote file afiedt.buf

  1  select start_date
  2      , end_date
  3      , (24 * extract(day from (end_date - start_date) day(9) to second))
  4          + extract(hour from (end_date - start_date) day(9) to second)
  5          + ((1/100) * extract(minute from (end_date - start_date) day(9) to second)) as "HOUR.MINUTE"
  6* from t
SQL> /

START_DATE          END_DATE            HOUR.MINUTE
------------------- ------------------- -----------
21-06-2011 14:00:00 21-06-2011 16:55:00        2.55
21-06-2011 07:00:00 21-06-2011 16:50:00         9.5
21-06-2011 07:20:00 21-06-2011 16:30:00         9.1

Il convient de noter pour ceux qui rencontrent ce code que les portions décimales sont des différences de minutes RÉELLES, et ne font pas partie d'une heure. .5, par conséquent, représente 50 minutes, ne pas 30 minutes.

4
Shannon Severance

Essaye ça

round(to_number(end_time - start_time) * 24)
2
reader_1000

Oracle représente les dates en nombre de jours, donc (end_time-start_time)*24 Vous donne des heures. Supposons que vous avez ce numéro (par exemple 2.9166667) Dans la colonne h. Ensuite, vous pouvez facilement le convertir au format souhaité avec: FLOOR(h) + (h-FLOOR(h))/100*60.

Exemple:

WITH diff AS (
    SELECT (TO_DATE('21-06-2011 16:55:00', 'DD-MM-YYYY HH24:MI:SS') - TO_DATE('21-06-2011 14:00:00', 'DD-MM-YYYY HH24:MI:SS'))*24 h
    FROM dual
) SELECT FLOOR(h) + (h-FLOOR(h))/100*60
FROM diff

Dans ton cas:

SELECT start_time, end_time,
    FLOOR((end_time-start_time)*24) + ((end_time-start_time)*24-FLOOR((end_time-start_time)*24))/100*60 AS hours_diff
FROM come_leav 
2
Crack

C'est une façon très laide de le faire, et cette première partie ne questionne pas exactement l'OP, mais elle donne un moyen d'obtenir des résultats en soustrayant 2 champs de date - dans mon cas, le CREATED_DATE et aujourd'hui représenté par SYSDATE:

SELECT FLOOR(ABS(MONTHS_BETWEEN(CREATED_DATE, SYSDATE)) / 12) || ' years, '  
|| (FLOOR(ABS(MONTHS_BETWEEN(CREATED_DATE, SYSDATE))) - 
   (FLOOR(ABS(MONTHS_BETWEEN(CREATED_DATE, SYSDATE)) / 12)) * 12) || ' months, '  
-- we take total days - years(as days) - months(as days) to get remaining days
|| FLOOR((SYSDATE - CREATED_DATE) -      -- total days
   (FLOOR((SYSDATE - CREATED_DATE)/365)*12)*(365/12) -      -- years, as days
   -- this is total months - years (as months), to get number of months, 
   -- then multiplied by 30.416667 to get months as days (and remove it from total days)
   FLOOR(FLOOR(((SYSDATE - CREATED_DATE)/365)*12 - (FLOOR((SYSDATE - CREATED_DATE)/365)*12)) * (365/12)))  
|| ' days, '   
-- Here, we can just get the remainder decimal from total days minus 
-- floored total days and multiply by 24       
|| FLOOR(
     ((SYSDATE - CREATED_DATE)-(FLOOR(SYSDATE - CREATED_DATE)))*24
   )
|| ' hours, ' 
-- Minutes just use the unfloored hours equation minus floored hours, 
-- then multiply by 60
|| ROUND(
       (
         (
           ((SYSDATE - CREATED_DATE)-(FLOOR(SYSDATE - CREATED_DATE)))*24
         ) - 
         FLOOR((((SYSDATE - CREATED_DATE)-(FLOOR(SYSDATE - CREATED_DATE)))*24))
       )*60
    )
|| ' minutes'  
AS AGE FROM MyTable`

Il fournit la sortie en tant que x années, x mois, x jours, x heures, x minutes. Il peut être reformaté comme vous le souhaitez en changeant les chaînes concaténées.

Pour répondre plus directement à la question, je suis allé de l'avant et j'ai écrit comment obtenir le nombre total d'heures avec des minutes comme hours.minutes:

select  
((FLOOR(end_date - start_date))*24)
|| '.' ||
ROUND(
       (
         (
           ((end_date - start_date)-(FLOOR(end_date - start_date)))*24
         ) - 
         FLOOR((((end_date - start_date)-(FLOOR(end_date - start_date)))*24))
       )*60
    )
from 
come_leav;   
0
vapcguy

Modifier: si vous avez besoin d'un numéro, alors

    trunc(end_date-start_date)*24+
    to_number(to_char(trunc(sysdate)+(end_date-start_date),'HH24.MI'))

Pour le résultat de chaîne, si delta est MOINS DE 24H: j'irais avec

    to_char(trunc(sysdate)+(end_date-start_date),'HH24.MI')

ou ...'HH24:MI:SS', mais c'est ma préférence personnelle.

pour plus de 24 heures, je préfixerais

    trunc(end_date-start_date)||"days "||
    to_char(trunc(sysdate)+(end_date-start_date),'HH24.MI')

Oui, comme Oracle compte en jours, avec une précision de quelques secondes, vous avez affaire à des problèmes arithmétiques. Une fois parce que vous ne gérez que des minutes (vous pouvez donc arrondir votre nombre à trunc(days*24*60+0.5)/24/60), mais l'imprécision arithmétique binaire sur le nombre 1/24/60 peut toujours vous causer des problèmes.

Edit2.1:

    to_char(24*(trunc(end_date)-trunc(start_date))+to_number(to_char(end_date,'HH24.MI'))-to_number(to_char(start_date,'HH24.MI')),'99999.99')

Mais le résultat pourrait être assez déroutant pour la moyenne, car la décimale 7,50 suggérerait sept heures et demie, ou au moins 7 heures 50 minutes, contrairement au temps écoulé de 7 heures 10 minutes.

0
vmatyi

essaye ça:

    SELECT
    TRIM(TO_CHAR(TRUNC(((86400*(end_time - start_time))/60)/60)-24*(trunc((((86400*(end_time - start_time))/60)/60)/24)),'00')) ||'.'||
    TRIM(TO_CHAR(TRUNC((86400*(end_time - start_time))/60)-60*(trunc(((86400*(end_time - start_time))/60)/60)),'00')) ||'.'  as duration
FROM come_leav;
0
Kevin Burton

Cette requête est très utile pour moi et si un organisme souhaite une différence entre start_date et end_date avec un temps comme HH: MI: SS, veuillez utiliser cette requête.

SELECT
    TRIM(TO_CHAR(TRUNC(((86400*(end_date - start_date))/60)/60)-24*(trunc((((86400(end_date - start_date))/60)/60)/24)),'00')) ||'.'||
    TRIM(TO_CHAR(TRUNC((86400*(actual_completion_date - actual_start_date))/60)-60*(trunc(((86400*(end_date - start_date))/60)/60)),'00')) ||'.'||
    TRIM(TO_CHAR(TRUNC((86400*(end_date - start_date)))-60*(trunc((86400*(end_date - actual_start_date))/60)),'00')) as duration  
FROM fnd_concurrent_requests; 
0