Bank Holidays in a Table?
My client maintains a table in their database with every day of the year and a flag to say if the day is a working day, a bank holiday or a weekend (Saturday/Sunday). Every now and again somebody takes the responsibility to flag the bank holidays in the future.
The primary purpose of the table is for setting appointments for agents or giving a date of completion based on x number of working days in the future, so generally the data is only required for a reasonably limited period of time around the current date.
A few issues spring to mind:
1) Somebody or something needs to maintain this table
2) Holding data for something that could be done via an algorithm
3) Database reads whenever making a working day calculation
Point (3) can be dealt with by caching etc. in a Transaction type system, however batch processes have the potential to cause problems, in fact, my client was suffering from a batch job running of 8+ hours.
Bank Holidays in an Algorithm
The solution provided to the client was to implement the Bank Holiday package attached to this post, enabling Bank Holiday and Next Working Day calculations without the need to perform data reads. The 8 hour batch job was reduced to seconds.
Examples for use:
1) Check if a date is a working day:
CREATE OR REPLACE FUNCTION IsWorkingDay
(FromDate IN DATE, NoofDays IN NUMBER DEFAULT 0)
RETURN VARCHAR2
AS
BEGIN
CASE
WHEN trim(to_char(fromdate + noofdays, ‘DAY’)) IN (‘SATURDAY’,'SUNDAY’)
THEN RETURN ‘FALSE’;
WHEN pkg_bank_holidays.fn_is_bank_holiday(fromdate + noofdays)
THEN RETURN ‘FALSE’;
ELSE
RETURN ‘TRUE’;
END CASE;
EXCEPTION
WHEN OTHERS THEN
RETURN ‘FALSE’;
END;
/
SQL> SELECT isWorkingDay(TO_DATE(’10-Aug-2010′,’dd-mon-yyyy’), 0) “Working Day?”
2 FROM DUAL
3 /
Working Day?
———————–
TRUE
2) Get the next or previous working day after a number of days in the future
CREATE OR REPLACE FUNCTION NextWorkingDay
( FromDate IN DATE DEFAULT SYSDATE, NoOfDays IN NUMBER DEFAULT 0 )
RETURN DATE AS
v_ReturnDate DATE ;
BEGIN
v_ReturnDate := FromDate + NoOfDays;
WHILE (IsWorkingDay(v_ReturnDate,0) = ‘FALSE’) LOOP
v_ReturnDate := v_ReturnDate + sign(NoOfDays);
END LOOP;
RETURN v_ReturnDate;
EXCEPTION
WHEN OTHERS THEN
RETURN null;
END NextWorkingDay;
/
SQL> SELECT NextWorkingDay(TO_DATE(’10-Aug-2010′,’dd-mon-yyyy’),5) “Next Work Day”
2 FROM DUAL
3 /
Next Work
———
16-AUG-10
read more »