Научитесь находить все рабочие дни между двумя заданными датами в Java. Рабочие дни считаются всеми буднями, за исключением всех праздников, выпадающих на будни. Как только у нас есть список рабочих дат, мы можем использовать API list.size(), чтобы получить общее количество рабочих дней.
В приведенных примерах используется необязательный список праздников и два предиката для проверки того, является ли день выходным или праздничным.
В обоих примерах используются следующие предикаты:
- Первый предикат isWeekend используется для проверки, является ли день выходным.
- Второй предикат isHoliday проверяет, является ли заданный день праздничным.
1. LocalDate.datesUntil() – Java 9
LocalDate.datesUntil() возвращает поток дат от начальной даты до конечной даты. Затем мы проверяем каждую дату в потоке по нашим двум предикатам.
public Stream<LocalDate> datesUntil(LocalDate endExclusive) //the end date is exclusive and should not be null.
Если день не является выходным или праздничным, мы считаем его рабочим днем. Мы получаем все такие даты и сохраняем их в списке с помощью метода агрегации потоков collect().
import java.time.DayOfWeek;import java.time.LocalDate;import java.time.temporal.ChronoUnit;import java.util.ArrayList;import java.util.List;import java.util.Optional;import java.util.function.Predicate;import java.util.stream.Stream;private static List<LocalDate> countBusinessDaysBetween_Java9(final LocalDate startDate,final LocalDate endDate,final Optional<List<LocalDate>> holidays) {// Validate method argumentsif(startDate == null || endDate == null) {throw new IllegalArgumentException("Invalid method argument(s)to countBusinessDaysBetween(" + startDate + "," + endDate + "," + holidays + ")");}// Predicate 1: Is a given date is a holidayPredicate<LocalDate> isHoliday = date -> holidays.isPresent()&& holidays.get().contains(date);// Predicate 2: Is a given date is a weekdayPredicate<LocalDate> isWeekend = date -> date.getDayOfWeek() == DayOfWeek.SATURDAY|| date.getDayOfWeek() == DayOfWeek.SUNDAY;// Iterate over stream of all dates and check each day against any weekday or holidayList<LocalDate> businessDays = startDate.datesUntil(endDate).filter(isWeekend.or(isHoliday).negate()).collect(Collectors.toList());return businessDays;}
Теперь мы можем использовать метод List.size(), чтобы получить количество рабочих дней, или можем использовать каждую дату в списке по своему усмотрению.
2. Поиск рабочих дней с помощью Stream API
Сначала мы получим общее количество дней между двумя заданными датами, используя API ChronoUnit.DAYS.between().
Затем мы перебираем поток всех дат от начальной до конечной даты, пока не достигнем предела daysBetween, и проверяем каждую дату на соответствие нашим двум предикатам isHoliday и isWeekend.
private static List<LocalDate> countBusinessDaysBetween_Java8(final LocalDate startDate,final LocalDate endDate,final Optional<List<LocalDate>> holidays){// Validate method argumentsif(startDate == null || endDate == null) {throw new IllegalArgumentException("Invalid method argument(s) tocountBusinessDaysBetween(" + startDate+ "," + endDate + "," + holidays + ")");}// Predicate 1: Is a given date is a holidayPredicate<LocalDate> isHoliday = date -> holidays.isPresent()&& holidays.get().contains(date);// Predicate 2: Is a given date is a weekdayPredicate<LocalDate> isWeekend = date -> date.getDayOfWeek() == DayOfWeek.SATURDAY|| date.getDayOfWeek() == DayOfWeek.SUNDAY;// Get all days between two dateslong daysBetween = ChronoUnit.DAYS.between(startDate, endDate);// Iterate over stream of all dates and check each day against any weekday or// holidayreturn Stream.iterate(startDate, date -> date.plusDays(1)).limit(daysBetween).filter(isHoliday.or(isWeekend).negate()).collect(Collectors.toList());}