Как вычесть 2 даты в оракуле, чтобы получить результат в час и минуту - PullRequest
9 голосов
/ 18 сентября 2011

Я хочу вычесть 2 даты и представить результат в часах и минутах одной десятичной цифрой.

У меня есть следующая таблица, и я делаю это таким образом, но результат не такой, как хотелось бы.

Есть небольшое отклонение, я уверен, что это простая арифметика, но я не понимаю это правильно.

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      

Я хочу получить результат (end_time-start_time), как показано ниже.

16:55- 14:00 = 2.55      
16:50-07:00 = 9.5      
16:30-7:20 = 9.1 and so on.    

Как я могу это сделать?

Ответы [ 8 ]

4 голосов
/ 18 сентября 2011
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

Следует отметить, что для тех, кто сталкивается с этим кодом, десятичные части представляют собой фактические минутные разницы, а не часть часа..5, следовательно, представляет 50 minutes, а не 30 minutes.

2 голосов
/ 18 сентября 2011

Oracle представляет даты в виде количества дней, поэтому (end_time-start_time)*24 дает вам часы.Предположим, у вас есть этот номер (например, 2.9166667) в столбце h.Затем вы можете легко преобразовать его в нужный формат: FLOOR(h) + (h-FLOOR(h))/100*60.

Пример:

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

В вашем случае:

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 голосов
/ 18 сентября 2011

Попробуйте это

round(to_number(end_time - start_time) * 24)
0 голосов
/ 30 июля 2016

Это очень уродливый способ сделать это, и эта первая часть точно не подвергается сомнению со стороны ОП, но она дает возможность получить результаты, вычитая 2 поля даты - в моем случае, CREATED_DATE и сегодня представлено 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`

Выводится в виде х лет, х месяцев, х дней, х часов, х минут. Его можно переформатировать, как вам угодно, изменив объединенные строки.

Чтобы более прямо ответить на вопрос, я пошел дальше и написал, как получить общее количество часов в минутах как 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 голосов
/ 09 апреля 2013

Этот запрос очень полезен для меня, и если какое-либо тело хочет разницы между start_date и end_date со временем, например, HH: MI: SS, используйте этот запрос.

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 голосов
/ 18 сентября 2011

Редактировать: если вам нужен номер, то

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

Для строкового результата, если дельта МЕНЬШЕ, ЧЕМ 24 Ч: я бы выбрал

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

или ...'HH24:MI:SS',но это мое личное предпочтение.

для сроков, превышающих 24ч, я бы поставил префикс с

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

Да, поскольку оракул считает в днях, с точностью до секунд, вы имеете дело с арифметическими проблемами.Однажды, потому что вы обрабатываете только минуты (так что вы можете округлить свое число до trunc(days*24*60+0.5)/24/60), но неточность двоичной арифметики на числе 1/24/60 может по-прежнему вызывать у вас проблемы.

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')

Но результат может быть довольно запутанным для среднего, так как десятичное число 7.50 будет означать семь с половиной часов или, по крайней мере, 7 часов 50 минут, в отличие от прошедшего времени 7 часов 10 минут.

0 голосов
/ 18 сентября 2011

вы можете работать с выпиской:

SELECT start_time, end_time, extract(HOUR FROM end_time-start_time) || '.' || extract(MINUTE FROM end_time-start_time)  
From come_leav;
0 голосов
/ 18 сентября 2011

попробуйте это:

    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;
...