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?
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
.
Essaye ça
round(to_number(end_time - start_time) * 24)
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
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;
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.
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;
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;