Есть ли в Oracle функция, вычисляющая разницу между двумя датами?

Есть ли в Oracle функция, вычисляющая разницу между двумя датами? Если нет, можно ли отобразить разницу между двумя датами в часах и минутах?

Запрос:

SELECT Round(max((EndDate - StartDate ) * 24), 2) as MaximumScheduleTime,
       Round(min((EndDate - StartDate) * 24), 2)  as MinimumScheduleTime,
       Round(avg((EndDate - StartDate) * 24), 2) as AveragegScheduleTime
FROM table1

person Tony    schedule 04.06.2009    source источник
comment
Вы нашли ответ, который искали?   -  person Mark Good    schedule 24.07.2009


Ответы (5)


В Oracle можно вычесть две даты. Результатом является FLOAT, который представляет количество дней между двумя датами. Вы можете выполнить простую арифметику с дробной частью, чтобы вычислить часы, минуты и секунды.

Вот пример:

SELECT TO_DATE('2000/01/02:12:00:00PM', 'yyyy/mm/dd:hh:mi:ssam')-TO_DATE('2000/01/01:12:00:00AM', 'yyyy/mm/dd:hh:mi:ssam') DAYS FROM DUAL

Результатов в: 1.5

person Mark Good    schedule 04.06.2009

Вы можете использовать эти функции:

1) ЭКСТРАКТ (элемент ИЗ временного_значения)

2) НОМТОЙМИНТЕРВАЛ (n, единица)

3) ЧИСЛОСИНТЕРВАЛ (n, единица).

Например :

SELECT EXTRACT(DAY FROM NUMTODSINTERVAL(end_time - start_time, 'DAY'))
   || ' days ' || 
   EXTRACT(HOUR FROM NUMTODSINTERVAL(end_time - start_time, 'DAY'))
   ||':'|| 
   EXTRACT(MINUTE FROM NUMTODSINTERVAL(end_time - start_time, 'DAY')) 
   ||':'||
   EXTRACT(SECOND FROM NUMTODSINTERVAL(end_time - start_time, 'DAY')) 
   "Lead Time"
FROM table;
person Michael Ellick Ang    schedule 04.06.2009
comment
ПРИМЕЧАНИЕ: это решение не сообщает часы для продолжительности ›24 часа. То есть, если разница между end_time и start_time больше 24 часов, это возвращает прошедшие часы за вычетом любых полных 24-часовых периодов. - person spencer7593; 05.06.2009
comment
привет, Спенсер, спасибо, что указали на это. я отредактировал решение. - person Michael Ellick Ang; 05.06.2009

С Oracle Dates это довольно тривиально: вы можете получить ВСЕГО (дни, часы, минуты, секунды) между двумя датами, просто вычитая их, или с небольшой модификацией вы можете получить Дни / Часы / Минуты / Секунды между ними.

http://asktom.oracle.com/tkyte/Misc/DateDiff.html

Кроме того, из приведенной выше ссылки:

Если вы действительно хотите, чтобы в вашей базе данных был атрибут «dateiff», вы можете просто сделать что-то вроде этого:

SQL> create or replace function datediff( p_what in varchar2, 
  2                                       p_d1   in date, 
  3                                       p_d2   in date ) return number 
  4  as 
  5      l_result    number; 
  6  begin 
  7      select (p_d2-p_d1) * 
  8             decode( upper(p_what), 
  9                     'SS', 24*60*60, 'MI', 24*60, 'HH', 24, NULL ) 
 10       into l_result from dual; 
 11 
 11      return l_result; 
 12  end; 
 13  /
Function created
person karim79    schedule 04.06.2009
comment
Пожалуйста, укажите использование, для чего используется p_what - person Donald N. Mafa; 21.10.2013

В: Есть ли в Oracle функция, которая вычисляет разницу между двумя датами?

Просто вычтите одно выражение даты из другого, чтобы получить разницу в количестве дней. Целая часть - это количество целых дней, дробная часть - это доля дня. Простая арифметика после этого умножьте на 24, чтобы получить часы.

В: Если нет, можно ли показать разницу между двумя датами в часах и минутах?

Это просто вопрос выражения продолжительности в виде целых часов и оставшихся минут.

Мы можем пойти по «старой школе», чтобы получить длительности в формате hhhh: mi, используя комбинацию простых встроенных функций:

SELECT decode(sign(t.maxst),-1,'-','')||to_char(floor(abs(t.maxst)/60))||
        decode(t.maxst,null,'',':')||to_char(mod(abs(t.maxst),60),'FM00')
         as MaximumScheduleTime
     , decode(sign(t.minst),-1,'-','')||to_char(floor(abs(t.minst)/60))||
        decode(t.minst,null,'',':')||to_char(mod(abs(t.minst),60),'FM00')
         as MinimumScheduleTime
     , decode(sign(t.avgst),-1,'-','')||to_char(floor(abs(t.avgst)/60))
        decode(t.avgst,null,'',':')||to_char(mod(abs(t.avgst),60),'FM00')
         as AverageScheduleTime
  FROM (
         SELECT round(max((EndDate - StartDate) *1440),0) as maxst
              , round(min((EndDate - StartDate) *1440),0) as minst
              , round(avg((EndDate - StartDate) *1440),0) as avgst
           FROM table1 
       ) t

Да, это непросто, но довольно быстро. Вот более простой случай, который лучше показывает, что происходит:

select dur                              as "minutes"
     , abs(dur)                         as "unsigned_minutes"
     , floor(abs(dur)/60)               as "unsigned_whole_hours"
     , to_char(floor(abs(dur)/60))      as "hhhh"
     , mod(abs(dur),60)                 as "unsigned_remainder_minutes"
     , to_char(mod(abs(dur),60),'FM00') as "mi"
     , decode(sign(dur),-1,'-','')      as "leading_sign"
     , decode(dur,null,'',':')          as "colon_separator"
  from (select round(( date_expr1 - date_expr2 )*24*60,0) as dur
          from ... 
       )

(замените date_expr1 и date_expr2 выражениями даты)

давай распакуем это

  • date_expr1 - date_expr2 возвращает разницу в количестве дней
  • умножьте на 1440 (24 * 60), чтобы получить продолжительность в минутах
  • round (или floor) для преобразования дробных минут в целые минуты
  • разделить на 60, целое частное - часы, остаток - минуты
  • abs функция для получения абсолютного значения (изменить отрицательные значения на положительные)
  • to_char формат модели FM00 дает две цифры (ведущие нули)
  • используйте функцию decode для форматирования знака минус и двоеточия (при необходимости)

Оператор SQL можно было бы сделать менее уродливым, используя функцию PL / SQL, которая принимает два аргумента DATE длительностью в (дробных) днях и возвращает формат hhhh: mi

(непроверено)

create function hhhhmi(an_dur in number)
return varchar2 deterministic
is
begin
  if an_dur is null then
     return null;
  end if;
  return decode(sign(an_dur),-1,'-','')
    || to_char(floor(abs(an_dur)*24))
    ||':'||to_char(mod((abs(an_dur)*1440),60),'FM00');
end;

С определенной функцией:

SELECT hhhhmi(max(EndDate - StartDate)) as MaximumScheduleTime
     , hhhhmi(min(EndDate - StartDate)) as MinimumScheduleTime
     , hhhhmi(avg(EndDate - StartDate)) as AverageScheduleTime
  FROM table1
person spencer7593    schedule 04.06.2009

Вы можете использовать функцию months_between, чтобы преобразовать даты в разницу в годах, а затем использовать интересующие вас десятичные годы:

CASE 
WHEN ( ( MONTHS_BETWEEN( TO_DATE(date1, 'YYYYMMDD'), 
                        TO_DATE(date1,'YYYYMMDD'))/12
        )
         BETWEEN Age1DecimalInYears AND Age2DecimalInYears 
      ) 
THEN 'It is between the two dates'
ELSE 'It is not between the two dates' 
END;

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

Ссылки: (найдено на www от 15.05.2015)
1. Oracle / PLSQL: функция MONTHS_BETWEEN
2. Oracle Справочный центр - MONTHS_BETWEEN

person RetroCoder    schedule 15.05.2015