Skip to main content

Calculating Business Days on Oracle

Abstract: A function you can use to calculate business days. Includes provisions for after hours calculations.
There are quite a number of examples already on the web for calculating business days on Oracle.
However, none of these did exactly what I needed for a job I was doing. What's different about my environment is the need to consider multiple geographic regions and to consider work hours and that different regions might have different work hours. Here are the deciding factors for how this function decides what to with timestamp after hours (both weekends and during the week)

  • If the start date is after the end of the work day, and before midnight, it is advanced to the beginning of next work day.
  • If the start date is before the beginning of the day (and therefore after midnight), it is advanced to the beginning of the current work day.
  • If the start date is on a Saturday, it is advanced to the beginning of work day on the following Monday.
  • If the start date is on a Sunday, it is advanced to the beginning of work day on the following Monday.
  • If the end date is after the end of the work day, and before midnight, it moved to the end of the day.
  • If the start date is before the beginning of the day (and therefore after midnight), it is advanced to the beginning of the current work day.
  • If the start date is on a Friday or Saturday it is moved to end of the previous Friday.
This function does not consider holidays, but could be modified to do so if you had a holiday table.

CREATE OR REPLACE FUNCTION bdays(start_date IN DATE, end_date IN DATE, region IN CHAR) 
RETURN NUMBER 
IS
  retval NUMBER(15,7);
  new_start_date date;
  new_end_date date;
  bdaystart number(15,15);
  bdayend number(15,15);
BEGIN
new_start_date := start_date;
new_end_date := end_date;
-- set defaults for business day start and end. Can be overridden per region
bdaystart := 7/24;
bdayend := 17/24;
if region='Europe' then
  new_start_date := new_start_date + 9/24;
  new_end_date := new_end_date + 9/24;
  bdaystart := 9/24;
  bdayend := 18.5/24;
end if;
if region='Asia-Pac' then
  new_start_date := new_start_date + 15/24;
  new_end_date := new_end_date + 15/24;
end if;
--Start After end of day, make start be start of next day
if new_start_date-trunc(new_start_date)>bdayend then
  new_start_date := TRUNC(new_start_date+1)+bdaystart;
end if;
--Start before start of day, make start be start of same day
if new_start_date-trunc(new_start_date) < bdaystart then
  new_start_date := TRUNC(new_start_date) + bdaystart;
end if;
--Start Saturday, make start be Monday start of day
if to_char(new_start_date,'D')=7 THEN
  new_start_date := TRUNC(new_start_date+2)+bdaystart;  
END IF;
--Start Sunday, make start be Monday start of day
if to_char(new_start_date,'D')=1 THEN
  new_start_date := TRUNC(new_start_date+1)+bdaystart;
END IF;
-- end after end of day, make end be end of day same day
if new_end_date-trunc(new_end_date) > bdayend then
  new_end_date := trunc(new_end_date) + bdayend;
end if;
-- end before start of day, make end be start of day the same day
if new_end_date-trunc(new_end_date) < bdaystart then
  new_end_date := trunc(new_end_date) + bdaystart;
end if;
--end on Saturday, make it be the end of the day on Friday
if to_char(new_end_date,'D')=7 then
  new_end_date := trunc(new_end_date-1) + bdayend;
end if;
--end on Sunday, make it be the end of the day on Friday
if to_char(new_end_date,'D')=1 then
  new_end_date := trunc(new_end_date-2) + bdayend;
end if;
--factor out weekend days
retval := new_end_date - new_start_date -
((TRUNC(new_end_date,'D') - TRUNC(new_start_date,'D'))/7)*2;
-- if holidays were to be calculated, the calculation would go here
-- if end is during nonbusiness hours, difference could be negative
if retval < 0 then 
  retval := 0;
end if;
RETURN(retval);
END;

Comments

Popular posts from this blog

Using App Icons In Oracle Apex (Part1)

 Recently with the introduction of Apex 4.2 and later Apex 4.2.1 the default published  packaged applications comes with a sleek logo just at the left-hand corner of the the login screen. Fig 1 Fig 2 Fig 3 If u want to use these cool  sprites that come with the later releases as said in the the former. From the above diagram, looking into the css  inside the  i / or anywhere that your images are stored navigate to the cloud/app_theme/css/4_1.css You would find the img.appIcon.  class  which houses all the sprite launchpad logos in the Fig 1 Inside the css, locate ------App Icons Image-- img.appIcon.project_tracking{background-position:-256px 0}img.appIcon.solar{background-position:-320px 0}img.appIcon.website{background-position:-384px 0}img.appIcon.apex_service{background-position:-448px 0}img.appIcon.solar_red{background-position:-512px 0}img.appIcon.sales{background-position:-576px 0}img.appIcon.data_modeler{background-position:0 -64px}img.appIcon.group_calen

Disabling of Password Expiration in Oracle Apex(Internal Workspace Admin)

This post was inspired by a  question  on the OTN APEX forum, which contains how to  reset set the password of the  Oracle Internal Workspace Admin    and  Set the account never to expire  The first bullet has so many blogs  talk about how to reset the password of the Internal Workspace. However, i am more intrigued with the second . To start of with It is not advisable to never expire accounts since its rudimental for user to always renew their accounts  prior to expiration. The default expiration of an account is mostly 180 days so hey whats the point going to do this again after 180 days?? . There are two methods that can be used to achieve this  Generic Never expiration of all User accounts (This should never be practiced in a production Environment All database users are assigned to something called a PROFILE . The profile controls two aspects of the users database access – the system resources available to the user and th

How does one add a day/hour/minute/second to a date value?

DATE is the datatype that we are all familiar  with when we think about representing date and time values. It has the ability to store the month, day, year, century, hours, minutes, and seconds. It is typically good for representing data for when something has happened or should happen in the future.  The problem with the DATE datatype is its' granularity  when trying to determine a time interval between two events when the events happen within a second of each other. This issue is solved with the TIMESTAMP datatype. In order to represent the date stored in a more readable format, the TO_CHAR function has traditionally been wrapped around the date: SQL> SELECT  TO_CHAR(hiredate,'DD.MM.YYYY:HH24:MI:SS')  "hiredate"   FROM employees; hiredate ------------------- 17.12.1980:00:00:00 20.02.1981:00:00:00 The SYSDATE pseudo-column shows the current system date and time. Adding 1 to SYSDATE will advance the date by 1 day. Use fractions to add hours, minut