Business Hours Calculations with Apex
Salesforce provides a simple mechanism for setting business hours in your organization. Just navigate to:
Setup -> Administration Setup -> Company Profile -> Business Hours
Which brings you to this screen:
You set the hours for each day of the week that the company is available. I’m using a single Business Hours record named Default. You can have multiple business hours in multiple time zones if you have a complex support organization. With business hours you can work in specific time zones and locations with:
- Cases
- Case escalation rules
- Case milestones in entitlement processes
This is accessible through Apex, but you will likely need to customize the logic to your needs. Salesforce thoughtfully provides a BusinessHours class, but it is very basic, just 3 methods. Since I needed to check if today was a business day and a few other things I had to write it myself.
Here is the Apex code:
1 public class BusinessDays { 2 3 private List<Boolean> businessDay = new Boolean[7]; 4 private List<Time> startHours = new Time [7]; 5 private List<Time> endHours = new Time [7]; 6 private Date knownSunday = date.newInstance(2013, 1, 6); 7 8 // Constructor creates businessDay array 9 public BusinessDays() { 10 11 BusinessHours bh = 12 [Select 13 SundayStartTime, MondayStartTime, TuesdayStartTime, 14 WednesdayStartTime, ThursdayStartTime, FridayStartTime, 15 SaturdayStartTime, SundayEndTime, MondayEndTime,TuesdayEndTime, 16 WednesdayEndTime, ThursdayEndTime, FridayEndTime,SaturdayEndTime 17 From BusinessHours 18 Where IsDefault=true]; 19 20 businessDay[0] = (bh.SundayStartTime != null); 21 businessDay[1] = (bh.MondayStartTime != null); 22 businessDay[2] = (bh.TuesdayStartTime != null); 23 businessDay[3] = (bh.WednesdayStartTime != null); 24 businessDay[4] = (bh.ThursdayStartTime != null); 25 businessDay[5] = (bh.FridayStartTime != null); 26 businessDay[6] = (bh.SaturdayStartTime != null); 28 29 startHours[0] = bh.SundayStartTime; 30 startHours[1] = bh.MondayStartTime; 31 startHours[2] = bh.TuesdayStartTime; 32 startHours[3] = bh.WednesdayStartTime; 33 startHours[4] = bh.ThursdayStartTime; 34 startHours[5] = bh.FridayStartTime; 35 startHours[6] = bh.SaturdayStartTime; 36 37 endHours[0] = bh.SundayEndTime; 38 endHours[1] = bh.MondayEndTime; 39 endHours[2] = bh.TuesdayEndTime; 40 endHours[3] = bh.WednesdayEndTime; 41 endHours[4] = bh.ThursdayEndTime; 42 endHours[5] = bh.FridayEndTime; 43 endHours[6] = bh.SaturdayEndTime; 44 45 } 46 47 // Check if today is a business day 48 public Boolean isBusinessDay(Date inputDate) { 49 // index i is index into the businessDay array based on inputDate 50 Integer i = Math.mod(Math.abs(this.knownSunday.daysBetween(inputDate)),7); 51 return (businessDay[i]); 52 } 53 54 // Get the start time 53 public Time getStartTime(Date inputDate) { 54 Integer i = Math.mod(Math.abs(this.knownSunday.daysBetween(inputDate.date)),7); 55 return (startHours[i]); 56 } 57 58 // Gets next business day, skipping non business days 59 public Date nextBusinessDay(Datetime inputDatetime) { 60 Integer i = 61 Math.mod(Math.abs(this.knownSunday.daysBetween(inputDatetime.date())),7); 62 Datetime returnDate = inputDatetime; 63 while (!businessDay[Math.mod(i, 7)]) { 64 i++; 65 returnDate = returnDate.addDays(1); 66 } 67 return returnDate.date; 68 } 69 70 }
I build 3 arrays. One to hold the days of the week the company is open, one to hold the start time for each day, and one to hold the end time of each day. I’m not using the end time array at the moment, it is available just in case.
Notice the variable knowSunday on line 6. You could also use the method Date.toStartOfWeek(), but you would have to match the indexes to the locale of your company. According to the Apex reference: “…the start of a week is Sunday in the United States locale, and Monday in European locales.” I usually work for US companies, but I’ve gotten in trouble before by making assumptions about locale dependent information when working for customers in Europe.
If you want to know if we are open for business today:
if (busDays.isBusinessDay(Date.today())) { ...
if (busDays.getStartTime(Date.today())) { ...
If you want to know what the next day we are open:
Datetime nextBusDay = busDays.nextBusinessDay(Datetime.now());
These are just a few of the possibilities. The customers I’ve worked for always seem to have their own unique rules for determining when to send the invoice, how to calculate the date in that custom field, and so on. The bad news is that almost nothing is pre-built in the API. The good news is that we can use Apex to implement whatever rules our customers dream up.