24

In Apex, how can you calculate the number of days between two dates excluding any days that fall on the weekend?

This would be similar to the existing Date.daysBetween() method.

There is a similar question that deals with the same issue in formula fields - Calculating Turnaround Time in Date Fields.

The question How Can I Tell the Day of the Week of a Date? provides methods for finding the day of the week in Apex.

4 Answers 4

21

So I wrote some code to handle this recently. It is completely configurable, and as efficient as can be.

The most important thing is to set the isWorkingDay array with the right flags (index 0 is Monday) and to make sure workingDaysInWeek matches the number of true flags in the array. After that the method will return a value for you.

//array of seven boolean indicating working days, Monday is index 0
private static final List<Boolean> isWorkingDay;
//count of the number of working days in the array
private static final Integer workingDaysInWeek;
static {
    //my real implementation uses the Salesforce BusinessHours Object to populate this array
    isWorkingDay = new List<Boolean> { true, true, true, true, true, false, false };
    //You will have real problems if this number does not match the number of true flags in the array
    workingDaysInWeek = 5;
}
// Monday is January 1st, 1900.
private static final Date monday = Date.newInstance(1900, 1, 1);
private static Integer getDayOfWeek(Date value) {
    return Math.mod(monday.daysBetween(value), 7);
}

public static Integer getWorkingDays(Date startDate, Date endDate) {
    //save some calculations when the number of working days is 0
    if(workingDaysInWeek == 0 || startDate == null || endDate == null) {
        return 0;
    } else {
        Integer difference = startDate.daysBetween(endDate);
        if(difference == 0) {
            //If the 2 dates are the same day check if the day is a working day or not
            return isWorkingDay[getDayOfWeek(startDate)] ? 1 : 0;
        } else if(workingDaysInWeek == 7) {
            //when every day is a working day return the difference
            return difference;
        } else {
            //The guts of the solution
            Integer wholeWeeks = Math.floor(difference / 7).intValue();
            Integer workingDays = wholeWeeks * workingDaysInWeek;
            Integer dayOfWeek = getDayOfWeek(endDate);
            for(Integer remainder = Math.mod(difference, 7); remainder >= 0; remainder--) {
                if(isWorkingDay[dayOfWeek]) {
                    workingDays++;
                }
                dayOfWeek--;
                if(dayOfWeek < 0) {
                    dayOfWeek = 6;
                }
            }
            return workingDays;
        }
    }
}
2
  • Nice, this seems a lot more flexible, especially when combined with the BusinessHours. Dec 12, 2012 at 21:24
  • This is truly helpful.. I was looking for something along these lines (plus learned a couple things just checking out the code as well). Thanks.
    – AMM
    Dec 12, 2012 at 21:48
4

Here is one possibile solution. It is a bit brute force as it examines every single day between the two inputs. So the further the dates are apart the more expensive it is to compute.

Also, it assumes that the startDate is less than the endDate to start with. So it won't return negative values like Date.daysBetween() can.

public static Integer daysBetweenExcludingWeekends(Datetime startDate, Datetime endDate) {
    Integer i = 0;

    while (startDate < endDate) {
        if (startDate.format('E') != 'Sat' && startDate.format('E') != 'Sun') {
            i++;
        }
        startDate = startDate.addDays(1);
    }

    return i;
}

Alternative attempt using daysBetween (not tested yet). Based on a C# example by Jon Egerton.

public static Integer daysBetweenExcludingWeekends(Datetime startDate, Datetime endDate) {
    //Work out days in range
    Integer days = startDate.date().daysBetween(endDate.date());

    //Remove most weekends by removing 2 in 7 days (rounded down)
    days -= ((integer)Math.floor((days / 7)) * 2);

    if (startDate.format('E') != 'Sat') {
        days -= 1;
    } else if (startDate.format('E') != 'Sun') {
        days -= 2;
    }

    return days;
}
3
  • You should be able to determine the start and end day, and then based on the number of days between them just rip out 2 out of every 7 (which some extra consideration being given based on there being a partial final week). Dec 12, 2012 at 20:51
  • @MichaelWelburn agreed. It will be possible to come up with a more flexible solution using the existing daysBetween() method and some division/modulo calculations. Dec 12, 2012 at 20:58
  • @MichaelWelburn I wrote something to solve this exact problem a few weeks ago, I've just posted it as an answer Dec 12, 2012 at 21:19
1

I think You can create a loop From Start date to end date . Check the day of date , If it is Sun and Sat count will (--) Otherwise Count++ in loop

    date startDate = date.newInstance(2018,10,01);
    date endDate = date.newInstance(2018,10,30);
    integer count=0;
    for(date d=startDate; d <= endDate; d=d.addDays(1)){

        DateTime myDateTime = (DateTime) d;
        String dayOfWeek = myDateTime.format('E');
        count++;
        if(dayOfWeek=='Sat' || dayOfWeek=='Sun'){
            count--;
        }
        System.debug('date==>'+dayOfWeek);
        System.debug('date==>'+d);
    }
    System.debug('date==>'+count);
1
  • 1
    Hi Deval, welcome to SFSE. This is essentially the same answer (albeit less efficient) as the one posted by Daniel Ballinger five years ago. Please try to make sure your answers aren't duplicative. If you approve of one that's already posted, you can upvote it.
    – David Reed
    Oct 26, 2018 at 12:17
0

You can use the business hours class from Salesforce to get this done easiy in apex.

You would first query for the business hours set in your system and then use the

Businesshours.diff(starttime,endtime) to get the time difference in milliseconds.

Reference: http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_businesshours.htm

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .