Расчет рабочих часов в указанном периоде


Я рассматривал случай рабочего дня с 08:00 по 17:00, включая обед с 12:00 по 13:00. Функция рассчитывает количество часов, которые попадают в заданный диапазон времени с учетом выходных дней (суббота и воскресенье), рамок рабочего дня и обеда.

CREATE OR REPLACE function worktime(beg_datetime in date, end_datetime in date)
return number
as
    kol_day number;
    type arr_table is table of number index by binary_integer;
    arr arr_table;
    res number default 0;
    
begin

   -- Чистим массив
   arr.delete;
   
 if beg_datetime < end_datetime then
   -- Расчет количества дней в заданном периоде дат
   kol_day := round(trunc(end_datetime) - trunc(beg_datetime));
   
   for i in 0..kol_day loop
      -- Проверка выходных дней (exclude Sunday, Saturday)
      if not to_char(beg_datetime + i, 'd') in (7, 1) then 
        -- Расчет количества рабочего времени по каждому дню
        arr(i) := case        
        -- если промежуточный день
        when not trunc(beg_datetime + i) in (trunc(beg_datetime), trunc(end_datetime)) 
            then 8
        -- если даты заданного дипазона совпадают
        when kol_day = 0 and trunc(beg_datetime + i) = trunc(end_datetime) then
           round(end_datetime - (beg_datetime + i), 3) 
        else case 
             -- если начало периода
             when trunc(beg_datetime + i) = trunc(beg_datetime) and
             to_char(beg_datetime, 'hh24') >= 8 and to_char(beg_datetime, 'hh24') < 12 
                then round((((trunc(beg_datetime) + 17/24) - beg_datetime)*24) - 1,3)
             when trunc(beg_datetime + i) = trunc(beg_datetime) and 
             to_char(beg_datetime, 'hh24') >= 13 and to_char(beg_datetime, 'hh24') < 17
                then round((((trunc(beg_datetime) + 17/24) - beg_datetime)*24),3)
             -- если конец периода
             when trunc(beg_datetime + i) = trunc(end_datetime) and
             to_char(end_datetime, 'hh24') >= 8 and to_char(end_datetime, 'hh24') < 12 
                then round((end_datetime - (trunc(end_datetime) + 8/24)) * 24,3)
             when trunc(beg_datetime + i) = trunc(end_datetime) and 
             to_char(end_datetime, 'hh24') >= 13 and to_char(end_datetime, 'hh24') < 17
                then round((end_datetime - (trunc(end_datetime ) + 8/24 + 1/24)) * 24,3)     
             -- ошибка
             else 0
             end
        end;
        
        -- Расчет суммароного рабочего времени за период
        res:= res + arr(i);
      
      end if;
                        
   end loop;

 else
 res:=-1;    
    DBMS_OUTPUT.PUT_LINE('Указан неверный диапазон дат!');
 
 end if;
   return res;
end;
/

Пример, вызова функции:

select worktime(to_date('07.04.2014 16:12:34','dd.mm.yyyy hh24:mi:ss'), to_date('20.04.2014 09:20:15','dd.mm.yyyy hh24:mi:ss')) RES from dual;

RES
---
72.791

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s