The weekend and holidays should be excluded. It is easy to exclude weekends, but the holiday are specific to each place and should be stored in an additional table. I store the holidays in a table HOLIDAYS_VD:
Select the time interval between two dates
The SQL query is adapted from here.
select count(*) from (
-- select * from (
select * from (
select dayinbetween, to_char( dayinbetween, 'DY' ) weekday from (
select startday+level-1 dayinbetween from (
select startday ,endday-startday diffdays from (
select to_date('01.02.2000','DD.MM.YYYY') endday, to_date('29.02.2000','DD.MM.YYYY') startday from dual
)
) connect by level <= diffdays+1
)
)where weekday not in ( 'SAT', 'SUN' )--all not weeknds in between
) a
left join holidays_vd h on a.dayinbetween=h.day
where h.day is null
order by dayinbetween;
It is almost right, but it does not return 0 is the two dates are the same. I did not corrected it and abandoned it because I needed a PL/SQL function. It is below, it is based on the query above and it seems to work fine.
PL/SQL function subtracting dates and exluding weekends and holidays
create or replace PACKAGE indicators AS
TYPE DateListType IS TABLE OF DATE;
function subtract_business_dates( startdate DATE, enddate DATE) return integer;
END ;
create or replace PACKAGE BODY indicators AS
function subtract_business_dates(
startdate DATE,
enddate DATE) return integer
IS
result INTEGER:=1;
dateList DateListType:=DateListType();
difference_days INTEGER;
BEGIN
difference_days:=trunc(enddate)-trunc(startdate);
if difference_days<0 then
RAISE_APPLICATION_ERROR(-20000, 'The first day is after the second date');
end if;
if difference_days=0 then
return 0;
end if;
dateList.extend(difference_days);
FOR i IN dateList.first..dateList.last
LOOP
dateList(i):=startdate+i;
END LOOP;
select count(*) into result from (
select * from (
select dayinbetween, to_char( dayinbetween, 'DY' ) weekday from (
select COLUMN_VALUE dayinbetween from (table(dateList))
)
)where weekday not in ( 'SAT', 'SUN' )--all not weeknds in between
) a
left join holidays_vd h on a.dayinbetween=h.day
where h.day is null
;
return result;
END;
END ;
Some tests to make sure that the function works well. Note, the table with holidays includes a test date 14.02.2000.
select indicators.subtract_business_dates(to_date('01.02.2000','DD.MM.YYYY'),to_date('29.02.2000','DD.MM.YYYY')) from dual;
select indicators.subtract_business_dates(to_date('04.02.2000','DD.MM.YYYY'),to_date('01.02.2000','DD.MM.YYYY')) from dual; --exception
select indicators.subtract_business_dates(to_date('03.02.2000','DD.MM.YYYY'),to_date('03.02.2000','DD.MM.YYYY')) from dual;--thu
select indicators.subtract_business_dates(to_date('03.02.2000','DD.MM.YYYY'),to_date('04.02.2000','DD.MM.YYYY')) from dual;--fri
select indicators.subtract_business_dates(to_date('03.02.2000','DD.MM.YYYY'),to_date('05.02.2000','DD.MM.YYYY')) from dual;--sat
select indicators.subtract_business_dates(to_date('03.02.2000','DD.MM.YYYY'),to_date('06.02.2000','DD.MM.YYYY')) from dual;--sun
select indicators.subtract_business_dates(to_date('03.02.2000','DD.MM.YYYY'),to_date('07.02.2000','DD.MM.YYYY')) from dual;--mon
select indicators.subtract_business_dates(to_date('03.02.2000','DD.MM.YYYY'),to_date('08.02.2000','DD.MM.YYYY')) from dual;--tue
select indicators.subtract_business_dates(to_date('04.02.2000','DD.MM.YYYY'),to_date('04.02.2000','DD.MM.YYYY')) from dual;--fri
select indicators.subtract_business_dates(to_date('04.02.2000','DD.MM.YYYY'),to_date('05.02.2000','DD.MM.YYYY')) from dual;--sat
select indicators.subtract_business_dates(to_date('04.02.2000','DD.MM.YYYY'),to_date('06.02.2000','DD.MM.YYYY')) from dual;--sun
select indicators.subtract_business_dates(to_date('04.02.2000','DD.MM.YYYY'),to_date('07.02.2000','DD.MM.YYYY')) from dual;--mon
select indicators.subtract_business_dates(to_date('04.02.2000','DD.MM.YYYY'),to_date('08.02.2000','DD.MM.YYYY')) from dual;--tue
select indicators.subtract_business_dates(to_date('10.02.2000','DD.MM.YYYY'),to_date('10.02.2000','DD.MM.YYYY')) from dual;--thu
select indicators.subtract_business_dates(to_date('10.02.2000','DD.MM.YYYY'),to_date('11.02.2000','DD.MM.YYYY')) from dual;--fri
select indicators.subtract_business_dates(to_date('10.02.2000','DD.MM.YYYY'),to_date('12.02.2000','DD.MM.YYYY')) from dual;--sat
select indicators.subtract_business_dates(to_date('10.02.2000','DD.MM.YYYY'),to_date('13.02.2000','DD.MM.YYYY')) from dual;--sun
select indicators.subtract_business_dates(to_date('10.02.2000','DD.MM.YYYY'),to_date('14.02.2000','DD.MM.YYYY')) from dual;--mon holiday
select indicators.subtract_business_dates(to_date('10.02.2000','DD.MM.YYYY'),to_date('15.02.2000','DD.MM.YYYY')) from dual;--tue
select indicators.subtract_business_dates(to_date('10.02.2000','DD.MM.YYYY'),to_date('16.02.2000','DD.MM.YYYY')) from dual;--wed