Use Java 8 to calculate the number of days between two dates, while ignoring some days of the week
I have three methods below The first one is simple It only counts the total number of days However, the second not only counts the number of days, but also ignores the day of the week passed to the method
My problem is that the third method is not always correct It should match the second method I guess it's related to leap years, because when it's incorrect, the difference is usually = 3 | 4
Additional information
I tried to simulate Excel's working day (serial_number, [return_type]) formula in some way
serial_number = startDate:Date - daysOfWeekToInclude:Array<Integer>
example
| A | B | C +---------+----------------------------------------------------+----------- 1 | Start | =DATE(2014,9,7) | 9/7/2014 2 | End | =DATE(2025,6,13) | 6/13/2025 3 | Include | ={1,2,4,6} (Mon,Tue,Thu,& Sat) | <Disp Only> 4 | Days | =SUM(INT((WEEKDAY($B$1-{1,6},1)+$B$2-$B$1)/7)) | 2248
Here is more information about this function: how to count / calculate the number of days between two dates in excel?
original image
method
>Just calculate the number of days between two dates
public static int simpleDaysBetween(final LocalDate start,final LocalDate end) { return (int) ChronoUnit.DAYS.between(start,end); }
>Use a cycle to calculate days, ignoring some days of the week
public static int betterDaysBetween(final LocalDate start,final LocalDate end,final List<DayOfWeek> ignore) { int count = 0; LocalDate curr = start.plusDays(0); while (curr.isBefore(end)) { if (!ignore.contains(curr.getDayOfWeek())) { count++; } curr = curr.plusDays(1); // Increment by a day. } return count; }
>Calculate the number of days Again, but no cycle
public static int bestDaysBetween(final LocalDate start,final List<DayOfWeek> ignore) { int days = simpleDaysBetween(start,end); if (days == 0) { return 0; } if (!ignore.isEmpty()) { int weeks = days / 7; int startDay = start.getDayOfWeek().getValue(); int endDay = end.getDayOfWeek().getValue(); int diff = weeks * ignore.size(); for (DayOfWeek day : ignore) { int currDay = day.getValue(); if (startDay <= currDay) { diff++; } if (endDay > currDay) { diff++; } } if (endDay > startDay) { diff -= endDay - startDay; } return days - diff; } return days; }
Complete code
import java.time.DayOfWeek; import java.time.LocalDate; import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.List; public class DayCounter { public static void main(String[] args) { final LocalDate start = LocalDate.of(2014,7); final LocalDate end = LocalDate.of(2025,13); List<DayOfWeek> ignore = Arrays.asList(DayOfWeek.SUNDAY,DayOfWeek.WEDNESDAY,DayOfWeek.FRIDAY); print(start); print(end); System.out.println(simpleDaysBetween(start,end)); System.out.println(betterDaysBetween(start,end,ignore)); System.out.println(bestDaysBetween(start,ignore)); } public static void print(LocalDate date) { System.out.printf("%s -> %s%n",date,date.getDayOfWeek()); } public static int simpleDaysBetween(final LocalDate start,final LocalDate end) { return (int) ChronoUnit.DAYS.between(start,end); } public static int betterDaysBetween(final LocalDate start,final List<DayOfWeek> ignore) { int count = 0; LocalDate curr = start.plusDays(0); while (curr.isBefore(end)) { if (!ignore.contains(curr.getDayOfWeek())) { count++; } curr = curr.plusDays(1); // Increment by a day. } return count; } public static int bestDaysBetween(final LocalDate start,final List<DayOfWeek> ignore) { int days = simpleDaysBetween(start,end); if (days == 0) { return 0; } if (!ignore.isEmpty()) { int weeks = days / 7; int startDay = start.getDayOfWeek().getValue(); int endDay = end.getDayOfWeek().getValue(); int diff = weeks * ignore.size(); for (DayOfWeek day : ignore) { int currDay = day.getValue(); if (startDay <= currDay) { diff++; } if (endDay > currDay) { diff++; } } if (endDay > startDay) { diff -= endDay - startDay; } return days - diff; } return days; } }
Solution
If we talk about the Java 8 API, why not use the Java 8 functionality
static long daysBetween(LocalDate start,LocalDate end,List<DayOfWeek> ignore) { return Stream.iterate(start,d->d.plusDays(1)) .limit(start.until(end,ChronoUnit.DAYS)) .filter(d->!ignore.contains(d.getDayOfWeek())) .count(); }