Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

calculate business days including holidays

i need to calculate the business days between two dates. ex : we have holiday(in USA) on july4th. so if my dates are date1 = 07/03/2012 date2 = 07/06/2012

no of business days b/w these dates should be 1 since july4th is holiday.

i have a below method to calclulate the business days which will only counts week ends but not holidays. is there any way to calculate holidays also....please help me on this.

  public static int getWorkingDaysBetweenTwoDates(Date startDate, Date endDate) {  
    Calendar startCal;  
    Calendar endCal;  
    startCal = Calendar.getInstance();  
    startCal.setTime(startDate);  
    endCal = Calendar.getInstance();  
    endCal.setTime(endDate);  
    int workDays = 0;  

    //Return 0 if start and end are the same  
    if (startCal.getTimeInMillis() == endCal.getTimeInMillis()) {  
        return 0;  
    }  

    if (startCal.getTimeInMillis() > endCal.getTimeInMillis()) {  
        startCal.setTime(endDate);  
        endCal.setTime(startDate);  
    }  

    do {  
        startCal.add(Calendar.DAY_OF_MONTH, 1);  
        if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY   
       && startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {  
            ++workDays;  
        }  
    } while (startCal.getTimeInMillis() < endCal.getTimeInMillis());  

    return workDays;  
}
like image 346
ran Avatar asked Jun 01 '12 16:06

ran


People also ask

Do you count holidays in business days?

Do business days include public holidays? Nope! Public holidays are excluded while calculating business days. The most common standard followed by regulations while defining business days is to count all days except Saturday, Sunday, and legal public holidays.

How do I calculate workdays in Excel exclude holidays and weekends?

If you'd like to calculate the difference between two dates while excluding weekends and holidays, use the NETWORKDAYS function instead. This also looks for 3 arguments: the start date, the end date, and optional holidays. Unlike the WORKDAY function, the NETWORKDAYS function does include or count the start day.


2 Answers

Let's pretend you have a list containing all the holidays, as you mentioned.

ArrayList<Integer> holidays = ...

Just add a condition to your if condition in your do-while:

do {
          startCal.add(Calendar.DAY_OF_MONTH, 1);
          if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY
          && startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY
          && !holidays.contains((Integer) startCal.get(Calendar.DAY_OF_YEAR))) {
              ++workDays;
          }
} while (startCal.getTimeInMillis() < endCal.getTimeInMillis());

For simplicity's sake, I've assumed holiday contains dates in the format identical to Calendar.DAY_OF_YEAR.

like image 45
SimplyPanda Avatar answered Nov 16 '22 03:11

SimplyPanda


Since the accepted answer still uses the obsolete Calendar class – here's my two cents using the newer Java Date and Time API available in the java.time package.

You have to get the dates of the holidays from somewhere, there is no standard Java library for it. That would be too localized anyway, since holidays heavily depend on your country and region (except for widely known holidays, such as Christmas or Easter).
You could get them from a holiday API, for instance. In the code below, I've hardcoded them as a Set of LocalDates.

Java 9

LocalDate startDate = LocalDate.of(2012, 3, 7);
LocalDate endDate = LocalDate.of(2012, 6, 7);

// I've hardcoded the holidays as LocalDates
// and put them in a Set
final Set<LocalDate> holidays = Set.of(
    LocalDate.of(2018, 7, 4)
);
// For the sake of efficiency, I also put the business days into a Set.
// In general, a Set has a better lookup speed than a List.
final Set<DayOfWeek> businessDays = Set.of(
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
);

List<LocalDate> allDates =

    // Java 9 provides a method to return a stream with dates from the
    // startdate to the given end date. Note that the end date itself is
    // NOT included.
    startDate.datesUntil(endDate)

        // Retain all business days. Use static imports from
        // java.time.DayOfWeek.*
        .filter(t -> businessDays.contains(t.getDayOfWeek()))

        // Retain only dates not present in our holidays list
        .filter(t -> !holidays.contains(t))

         // Collect them into a List. If you only need to know the number of
         // dates, you can also use .count()
        .collect(Collectors.toList());

Java 8

The method LocalDate.datesUntil is not available in Java 8, so you have to obtain a stream of all dates between those two dates in a different manner. We must first count the total number of days in between using the ChronoUnit.DAYS.between method.

long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate);

Then we must generate a sequence of integers exactly as long as the number of days between the start and end date, and then create LocalDates from it, starting at the start date.

IntStream.iterate(0, i -> i + 1)
    .limit(numOfDaysBetween)
    .mapToObj(startDate::plusDays)

Now we have a Stream<LocalDate>, and you can then use the remaining part of the Java 9 code. You also need to replace the usage of Set.of(), because it's not available in Java 8. Probably by new HashSet<>(Arrays.asList(MONDAY...FRIDAY)).

like image 182
MC Emperor Avatar answered Nov 16 '22 04:11

MC Emperor