If we are talking about the Java 8 API, why not use the Java 8 features, therefore ...
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(); }
Starting with Java 9, we can use an even simpler
static long daysBetween(LocalDate start, LocalDate end, List<DayOfWeek> ignore) { return start.datesUntil(end) .filter(d->!ignore.contains(d.getDayOfWeek())) .count(); }
Although it might be worth using Set with a better linear search than List :
static long daysBetween(LocalDate start, LocalDate end, List<DayOfWeek> ignore) { if(ignore.isEmpty()) return start.until(end, ChronoUnit.DAYS); EnumSet<DayOfWeek> set = EnumSet.copyOf(ignore); return start.datesUntil(end) .filter(d->!ignore.contains(d.getDayOfWeek())) .count(); }
You can consider changing the parameter to Set<DayOfWeek> , since it is not only more efficient, but also better suited for real-world use cases. Instead of Arrays.asList(DayOfWeek.SUNDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY) you can pass EnumSet.of(DayOfWeek.SUNDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY) , but you can also use EnumSet.range(DayOfWeek.MONDAY, DayOfWeek.FRIDAY) to indicate typical business days.
You can avoid iteration throughout the days, but this requires special attention to corner cases and, therefore, rigorous testing. And pay off only for really large ranges. For completeness, this is an optimized option:
static long daysBetween(LocalDate start, LocalDate end, Set<DayOfWeek> ignore) { long d1 = start.toEpochDay(), d2 = end.toEpochDay(); if(d1 > d2) throw new IllegalArgumentException(); if(ignore.isEmpty()) return d2 - d1; int incompleteWeek = 0; DayOfWeek startDoW = start.getDayOfWeek(), endDoW = end.getDayOfWeek(); if(startDoW != endDoW) { for(int v1 = startDoW.getValue(), v2 = endDoW.getValue(); v1 != v2 && d1 < d2; v1 = v1%7+1, d1++) { if(!ignore.contains(DayOfWeek.of(v1))) incompleteWeek++; } } return incompleteWeek + (d2 - d1) * (7 - ignore.size()) / 7; }
Here, the performance of searching ignore sets does not matter, since we are looking for no more than six values, however, using Set , that is, the absence of duplicates, allows us to use the size of the sets to calculate the number of days contained in the full weeks of the range. Full weeks have the same day of the week for the start and (exclusive) end dates. Thus, the code should only iterate over the days until the start and end days of the week match.