31 июля 2008 г.

Working days between two dates

Функция Оказывается в Oracle нет такой стандартной функции для подсчета количества рабочих дней между двумя датами. Есть функия для подсчета количества месяцев между двумя датами MONTHS_BETWEEN:

MONTHS_BETWEEN
Calculates the number of months between two dates.

В инете поискала такие самописные функции, которые бы считали количество месяцев между двумя датами. Больше всех понравилась этот метод подсчета, описанная в Tips of the Week на сайте Oracle, мне кажется он самый оптимальный из тех, что я посмотрела:

create table date_test (start_dt date, end_dt date);

select start_dt,
end_dt,
trunc(end_dt - start_dt) age,
(trunc(end_dt - start_dt) - ((case
WHEN (8 - to_number(to_char(start_dt, 'D'))) >
trunc(end_dt - start_dt) + 1 THEN 0
ELSE
trunc((trunc(end_dt - start_dt) - (8 - to_number(to_char(start_dt, 'D')))) / 7) + 1
END) + (case
WHEN mod(8 - to_char(start_dt, 'D'), 7) >
trunc(end_dt - start_dt) - 1 THEN
0
ELSE
trunc((trunc(end_dt - start_dt) -
(mod(8 - to_char(start_dt, 'D'), 7) + 1)) / 7) + 1
END))) workingdays
from date_test

Здесь он считает суммарное количество суббот и воскресений и отнимает от общего количества дней между двумя датами. Правда, глубоко вникать не стала, на тествых датах работает правильно. Можно переписать в функцию:
create or replace function working_days_between (start_dt in date, end_dt in date) return number is
wdays number;
begin
select (trunc(end_dt - start_dt) - ((case
WHEN (8 - to_number(to_char(start_dt, 'D'))) >
trunc(end_dt - start_dt) + 1 THEN 0
ELSE
trunc((trunc(end_dt - start_dt) - (8 - to_number(to_char(start_dt, 'D')))) / 7) + 1
END) + (case
WHEN mod(8 - to_char(start_dt, 'D'), 7) >
trunc(end_dt - start_dt) - 1 THEN 0
ELSE
trunc((trunc(end_dt - start_dt) - (mod(8 - to_char(start_dt, 'D'), 7) + 1)) / 7) + 1
END))) into wdays from dual;
return wdays;
end working_days_between;