Как вычесть 2 даты в оракуле, чтобы получить результат в час и минуту

Я хочу вычесть 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.    

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


person Macky    schedule 18.09.2011    source источник
comment
Ожидаемый результат выглядит довольно нелепо. Это должно быть так. 16:55–14:00 = 2:55 или 2,92 16:50–07:00 = 9:50 или 9,83 16:30–7:20 = 9:10 или 9:17   -  person Thinhbk    schedule 19.09.2011
comment
смогу ли я получить его в виде 2.55. Я фактически сообщаю время и время ожидания и вычисляю разницу в часах и минутах. Спасибо.   -  person Macky    schedule 19.09.2011
comment
Я должен сказать, что это, вероятно, один из самых хорошо написанных вопросов SQL, которые я видел на Stack Overflow. Я знаю, вы, вероятно, давно забыли об этом, но я должен был это сказать.   -  person user5670895    schedule 22.01.2016


Ответы (8)


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.

person Shannon Severance    schedule 18.09.2011
comment
Ниже приведен результат, когда я запускаю это. Но, пожалуйста, взгляните на последнюю строку, она дает мне 7,1, тогда как мне нужно, чтобы она была 7,5 (14-6,50), не ставя под угрозу другие цифры. Спасибо за вашу помощь START_TIME END_TIME 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 22-06-2011 07:20:00 22-06-2011 16:30:00 9.1 23-06-2011 07:20:00 23-06-2011 16 :30:00 9.1 21-06-2011 06:50:00 21-06-2011 14:00:00 7.1 - person Macky; 19.09.2011
comment
@Маки. Это бессмысленно. Вы просили вычесть время, чтобы получить hours.minutes. (Что не имеет особого смысла для начала.) 14:00 минус 6:50 — это семь часов десять минут или 7,1. Вы говорите, что хотите, чтобы 2:00 - 1:59 были 0,41 в течение одной минуты, а 1:41 - 1:00 были 0,41 в течение сорока одной минуты? - person Shannon Severance; 19.09.2011
comment
@ShannonSeverance Отличная работа по расшифровке того, что он хотел, и кода выше. В качестве примечания к коду в сообщении, из-за нечетного требования ОП следует отметить, что десятичная дробь отображает фактические минуты, а не дробные части часа. Я представил правку. - person vapcguy; 06.12.2016

Попробуй это

round(to_number(end_time - start_time) * 24)
person reader_1000    schedule 18.09.2011
comment
Спасибо за вашу помощь. Но результат не тот, что я хотел. См. ниже SQL› выберите to_number(end_time-start_time)*24 from come_leav; TO_NUMBER(END_TIME-START_TIME)*24 ---------------------------------- 2,9166667 9,8333333 9,1666667 9,1666667 9,1666667 7,1666667 - person Macky; 18.09.2011
comment
У меня не установлена ​​база данных оракула, поэтому я не смог проверить заданный мной запрос. Извините за неправильный/неполный ответ. - person reader_1000; 18.09.2011
comment
Это точно в том смысле, что дает десятичный эквивалент минут - просто нужно умножить эту часть на 60. Проблема заключается в нечетном требовании, когда ОП нуждался в нем как HH.MM. - person vapcguy; 06.12.2016
comment
FLOOR((end_time - start_time) * 24) || '.' || ROUND(((end_time - start_time) * 24) - FLOOR((end_time - start_time) * 24)*60) скорее всего, как ОП должен будет его использовать. - person vapcguy; 06.12.2016

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 
person piotrp    schedule 18.09.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;
person Kevin Burton    schedule 18.09.2011
comment
Спасибо за вашу помощь, я получаю желаемые результаты, но не могу получить их без конкатенации, я имею в виду окончательный результат, потому что я должен использовать это для расчета разницы во времени входа и выхода. - person Macky; 18.09.2011
comment
@Macky, если вам нужно использовать его для расчета, результаты в вашем исходном сообщении верны. 1 ч 30 мин — это час с половиной половина, половина — 0,5, поэтому 1 ч 30 мин = 1,5 часа. - person roselan; 18.09.2011
comment
Привет, Рослан, ты прав, но я хочу, чтобы расчет был выполнен так, как я просил, потому что я хочу найти разницу во времени между временем начала и временем окончания. Поэтому я хочу, чтобы результат, как запрошено ранее, то есть 16:55-14:00, был 2,55, а не 2,916667. поэтому, пожалуйста, посоветуйте более простой способ сделать это, спасибо... - person Macky; 18.09.2011
comment
@Macky, я отредактировал сообщение ... заменил разделитель : на . и удалил секунды из строки. - person Kevin Burton; 19.09.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 все равно может вызвать у вас проблемы.

Редактировать 2.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 минут.

person vmatyi    schedule 18.09.2011
comment
выберите start_time, end_time, to_char(trunc(sysdate)+(end_time-start_time),'HH24.MI') из come_leav; S_TIME E_TIME T_C 21-06-2011 14:00:00 21-06-2011 16:55:00 02.55 21-06-2011 07:00:00 21-06-2011 16:50:00 09.50 21-06-2011 07:20:00 21-06-2011 16:30:00 09.10 22-06-2011 07:20:00 22-06-2011 16:30:00 09.10 23-06-2011 07:20:00 23-06 -2011 16:30:00 09.10 21-06-2011 06:50:00 21-06-2011 14:00:00 07.10. Пожалуйста, посмотрите на последний результат (14-06.50) возвращает 07.10, где, как я хочу, как (14-06.50) = 7,5. Любое предложение, как преодолеть это .. Спасибо миллион за вашу помощь. - person Macky; 19.09.2011
comment
Вот что я получаю. Кажется, исправил последний, но, пожалуйста, взгляните на первый, он дает -88,45 вместо 2,55. Пожалуйста, помогите, мне нужно понять это правильно. Спасибо.. START_TIME END_TIME --------- ------------------- TRUNC(END_TIME-START_TIME)+TO_CHAR(TO_NUMBER(TO_CHAR(END_TIME,'HH24) .MI'))-TO_NUMBER(TO_CHAR(START_TI --------------------------------------- ----------------------------- 21-09-2011 14:00:00 21-06-2011 16:55:00 - 88.45 21-06-2011 07:00:00 21-06-2011 16:50:00 9.5 23-06-2011 07:20:00 23-06-2011 16:30:00 9.1 21-06-2011 06: 50:00 21-06-2011 14:00:00 7.5 - person Macky; 19.09.2011
comment
Хорошо, ошиблись, 2.1 теперь работает как хотите. Но не удалось получить 2,55, так как они относятся к разным месяцам, а конец меньше начала, поэтому в результате должно получиться большое отрицательное число. (Если вы удалите часть 24 * (...) +, вы получите 2,55, но вы не должны) - person vmatyi; 21.09.2011
comment
Привет @vmatyi, извини. Да, эта дата находится в другом месяце. Это должно быть в том же месяце, или я должен сказать, что это будет в тот же день. Я нахожу разницу, вычитая time_out из time_in, чтобы получить hr.min. Это для данных, полученных от часового механизма, который отслеживает время прихода и ухода, а также сообщает об общих часах и поздних часах. Я делаю это так. return(trunc(:et_time-:st_time)+to_char(to_number(to_char(:et_time, 'HH24.MI'))-to_number(to_char(:st_time,'HH24.MI')),'9.99')); - person Macky; 21.09.2011

Этот запрос очень полезен для меня, и если кому-то нужна разница между 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; 
person Ratan Kumar Nahak    schedule 09.04.2013

Это очень уродливый способ сделать это, и эта первая часть точно не ставит под сомнение OP, но дает возможность получить результаты, вычитая 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;   
person vapcguy    schedule 29.07.2016

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

SELECT start_time, end_time, extract(HOUR FROM end_time-start_time) || '.' || extract(MINUTE FROM end_time-start_time)  
From come_leav;
person roselan    schedule 18.09.2011
comment
я получаю следующую ошибку: SQL> SELECT start_time, end_time, extract(HOUR FROM end_time-start_time) || '.' || извлечь (МИНУТА ОТ конечного_времени-начального_времени) Из прихода_уйти; ВЫБЕРИТЕ start_time, end_time, извлечение (ЧАС ОТ end_time-start_time) || '.' || извлечь (МИНУТА ОТ конечного_времени-начального_времени) из come_leav * ОШИБКА в строке 1: ORA-30076: недопустимое поле извлечения для источника извлечения - person Macky; 19.09.2011
comment
@roselan Я получаю ту же ошибку, что и Маки. Было бы здорово, если бы это работало или можно было бы заставить работать. - person vapcguy; 29.07.2016