Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to skip weekends while adding days to LocalDate in Java 8?

Other answers here refer to Joda API. I want to do it using java.time.

Suppose today's date is 26th Nov 2015-Thursday, when I add 2 business days to it, I want the result as Monday 30th Nov 2015.

I am working on my own implementation but it would be great if something already exists!

EDIT:

Is there a way to do it apart from looping over?

I was trying to derive a function like:

Y = f(X1,X2) where Y is actual number of days to add, X1 is number of business days to add,  X2 is day of the week (1-Monday to 7-Sunday) 

Then given X1 and X2 (derived from day of week of the date), we can find Y and then use plusDays() method of LocalDate.

I have not been able to derive it so far, its not consistent. Can anyone confirm that looping over until desired number of workdays are added is the only way?

like image 248
Anmol Gupta Avatar asked Nov 26 '15 15:11

Anmol Gupta


People also ask

How do you check if a date falls on weekend or holiday with Java 8?

Checking a Weekend using LocalDateget(ChronoField. DAY_OF_WEEK) method returns an integer value in the range of 1 to 7. Each integer value represents a different weekday. 1 represents Monday, and so on 6 represents Saturday and 7 represents Sunday.

How do you add only business days in Java?

1. Adding Business Days. It uses two Predicate instances isHoliday and isWeekend . We repeatedly increment the LocalDate instance by 1 using the method plusDays() and check if the new date satisfies anyone of the given predicates.

How do I add days in LocalDate?

The plusDays() method of a LocalDate class in Java is used to add the number of specified day in this LocalDate and return a copy of LocalDate. For example, 2018-12-31 plus one day would result in 2019-01-01. This instance is immutable and unaffected by this method call.

What is the difference between LocalDate and LocalDateTime?

LocalDate – represents a date (year, month, day) LocalDateTime – same as LocalDate, but includes time with nanosecond precision. OffsetDateTime – same as LocalDateTime, but with time zone offset.


1 Answers

The following method adds days one by one, skipping weekends, for positive values of workdays:

public LocalDate add(LocalDate date, int workdays) {     if (workdays < 1) {         return date;     }      LocalDate result = date;     int addedDays = 0;     while (addedDays < workdays) {         result = result.plusDays(1);         if (!(result.getDayOfWeek() == DayOfWeek.SATURDAY ||               result.getDayOfWeek() == DayOfWeek.SUNDAY)) {             ++addedDays;         }     }      return result; } 

After some fiddling around, I came up with an algorithm to calculate the number of workdays to add or subtract.

/**  * @param dayOfWeek  *            The day of week of the start day. The values are numbered  *            following the ISO-8601 standard, from 1 (Monday) to 7  *            (Sunday).  * @param businessDays  *            The number of business days to count from the day of week. A  *            negative number will count days in the past.  *   * @return The absolute (positive) number of days including weekends.  */ public long getAllDays(int dayOfWeek, long businessDays) {     long result = 0;     if (businessDays != 0) {         boolean isStartOnWorkday = dayOfWeek < 6;         long absBusinessDays = Math.abs(businessDays);          if (isStartOnWorkday) {             // if negative businessDays: count backwards by shifting weekday             int shiftedWorkday = businessDays > 0 ? dayOfWeek : 6 - dayOfWeek;             result = absBusinessDays + (absBusinessDays + shiftedWorkday - 1) / 5 * 2;         } else { // start on weekend             // if negative businessDays: count backwards by shifting weekday             int shiftedWeekend = businessDays > 0 ? dayOfWeek : 13 - dayOfWeek;             result = absBusinessDays + (absBusinessDays - 1) / 5 * 2 + (7 - shiftedWeekend);         }     }     return result; } 

Usage Example:

LocalDate startDate = LocalDate.of(2015, 11, 26); int businessDays = 2; LocalDate endDate = startDate.plusDays(getAllDays(startDate.getDayOfWeek().getValue(), businessDays));  System.out.println(startDate + (businessDays > 0 ? " plus " : " minus ") + Math.abs(businessDays)         + " business days: " + endDate);  businessDays = -6; endDate = startDate.minusDays(getAllDays(startDate.getDayOfWeek().getValue(), businessDays));  System.out.println(startDate + (businessDays > 0 ? " plus " : " minus ") + Math.abs(businessDays)         + " business days: " + endDate); 

Example Output:

2015-11-26 plus 2 business days: 2015-11-30

2015-11-26 minus 6 business days: 2015-11-18

like image 81
Modus Tollens Avatar answered Sep 28 '22 04:09

Modus Tollens