一般来说,有一张假期表是可行的,但是由于某些假期正在移动,因此需要进行一些维护。例如,感恩节是 11 月的第四个星期四,即从 11 月 22 日到 11 月 28 日。
您还可以使用 Oracle 内置调度程序。通常它用于控制SCHEDULER JOBS,但我看不出有什么理由不应该将它用于其他用途。
首先创建一个联邦假日列表,例如:
BEGIN
DBMS_SCHEDULER.CREATE_SCHEDULE(schedule_name => 'CHRISTMAS', repeat_interval => 'FREQ=YEARLY;INTERVAL=1;BYDATE=1225', comments => 'December 25');
DBMS_SCHEDULER.CREATE_SCHEDULE(schedule_name => 'COLUMBUS_DAY', repeat_interval => 'FREQ=MONTHLY;BYMONTH=OCT;BYDAY=2 MON', comments => '2nd Monday in October');
DBMS_SCHEDULER.CREATE_SCHEDULE(schedule_name => 'INDEPENDENCE_DAY', repeat_interval => 'FREQ=YEARLY;INTERVAL=1;BYDATE=0704', comments => 'July 4');
DBMS_SCHEDULER.CREATE_SCHEDULE(schedule_name => 'MARTIN_LUTHER_KING_DAY', repeat_interval => 'FREQ=MONTHLY;BYMONTH=JAN;BYDAY=3 MON', comments => '3rd Monday in January');
DBMS_SCHEDULER.CREATE_SCHEDULE(schedule_name => 'MEMORIAL_DAY', repeat_interval => 'FREQ=MONTHLY;BYMONTH=MAY;BYDAY=-1 MON', comments => 'Last Monday of May');
DBMS_SCHEDULER.CREATE_SCHEDULE(schedule_name => 'NEW_YEARS_DAY', repeat_interval => 'FREQ=YEARLY;INTERVAL=1;BYDATE=0101', comments => 'January 1');
DBMS_SCHEDULER.CREATE_SCHEDULE(schedule_name => 'THANKSGIVING', repeat_interval => 'FREQ=MONTHLY;BYMONTH=NOV;BYDAY=4 THU', comments => '4th Thursday in November');
DBMS_SCHEDULER.CREATE_SCHEDULE(schedule_name => 'WASHINGTONS_BIRTHDAY', repeat_interval => 'FREQ=MONTHLY;BYMONTH=FEB;BYDAY=3 MON', comments => '3rd Monday in February');
DBMS_SCHEDULER.CREATE_SCHEDULE(schedule_name => 'WEEKEND', repeat_interval => 'FREQ=DAILY;INTERVAL=1;BYDAY=SAT,SUN');
-- Combined schedule for all federal holidays
DBMS_SCHEDULER.CREATE_SCHEDULE(schedule_name => 'FEDERAL_HOLIDAYS', repeat_interval => 'FREQ=DAILY;INTERSECT=CHRISTMAS,INDEPENDENCE_DAY,MARTIN_LUTHER_KING_DAY,MEMORIAL_DAY,NEW_YEARS_DAY,THANKSGIVING,WASHINGTONS_BIRTHDAY');
END;
/
查看Calendaring Syntax,了解如何指定repeat_interval。
然后您可以使用程序DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING 获取您的日期:
CREATE OR REPLACE FUNCTION LAST_BUSINESS_DAY(today IN TIMESTAMP DEFAULT SYSTIMESTAMP) RETURN TIMESTAMP AS
return_date_after TIMESTAMP := TRUNC(today);
next_run_date TIMESTAMP;
BEGIN
LOOP
DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('FREQ=DAILY;INTERVAL=1;EXCLUDE=FEDERAL_HOLIDAYS,WEEKEND', NULL, return_date_after, next_run_date);
EXIT WHEN next_run_date >= LAST_DAY(TRUNC(today));
return_date_after := next_run_date;
END LOOP;
RETURN return_date_after;
END LAST_BUSINESS_DAY;