DateSpan

日付期間に関する処理のために。。

import java.time.LocalDate;
import java.time.Period;
import java.util.AbstractMap;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 日付期間インターフェース. AbstractMap.SimpleEntry<LocalDate, LocalDate>;開始日と終了日とする期間に対する日付処理
 */
@FunctionalInterface
public interface DateSpan extends Supplier<AbstractMap.SimpleEntry<LocalDate, LocalDate>>{
   /**
    * 期間内か否か?.
    * @param date 検査対象日
    * @return true=期間内である
    */
   public default boolean inRange(LocalDate date){
      AbstractMap.SimpleEntry<LocalDate, LocalDate> pair = get();
      return pair.getKey().compareTo(date) <= 0 && date.compareTo(pair.getValue()) <= 0;
   }

   /**
    * 期間と重複する?.
    * @param start 検査対象開始日
    * @param end 検査対象終了日
    * @return true=重複する
    */
   public default boolean isBook(LocalDate start, LocalDate end){
      AbstractMap.SimpleEntry<LocalDate, LocalDate> pair = get();
      return start.compareTo(pair.getValue()) <= 0 && end.compareTo(pair.getKey()) >= 0;
   }

   /**
    * 重複日数を抽出.
    * @param start 検査対象開始日
    * @param end 検査対象終了日
    * @return 重複した日数
    */
   public default long bookDays(LocalDate start, LocalDate end){
      AbstractMap.SimpleEntry<LocalDate, LocalDate> pair = get();
      if (start.compareTo(pair.getValue()) <= 0 && end.compareTo(pair.getKey()) >= 0){
         LocalDate sdate = pair.getKey().compareTo(start) <= 0 && start.compareTo(pair.getValue()) <= 0 ? start : pair.getKey();
         LocalDate edate = pair.getKey().compareTo(end) <= 0 && end.compareTo(pair.getValue()) <= 0 ? end : pair.getValue();
         return Period.between(sdate, edate).getDays() + 1;
      }
      return 0;
   }

   /**
    * 重複期間を抽出.
    * @param start 検査対象開始日
    * @param end 検査対象終了日
    * @return 重複期間の開始日と終了の AbstractMap.SimpleEntry、重複がなければ null
    */
   public default AbstractMap.SimpleEntry<LocalDate, LocalDate> bookPair(LocalDate start, LocalDate end){
      AbstractMap.SimpleEntry<LocalDate, LocalDate> pair = get();
      if (start.compareTo(pair.getValue()) <= 0 && end.compareTo(pair.getKey()) >= 0){
         return new AbstractMap.SimpleEntry<LocalDate, LocalDate>(
               pair.getKey().compareTo(start) <= 0 && start.compareTo(pair.getValue()) <= 0 ? start : pair.getKey()
               , pair.getKey().compareTo(end) <= 0 && end.compareTo(pair.getValue()) <= 0 ? end : pair.getValue());
      }
      return null;
   }

   /**
    * 期間リスト→重複期間リストの抽出.
    * @param targets 検査対象になる開始日と終了日の期間ペアのリスト
    * @return 複期間の開始日と終了の AbstractMap.SimpleEntryのリスト、重複がなければ size = 0
    */
   public default List<SimpleEntry<LocalDate, LocalDate>> bookPair(List<SimpleEntry<LocalDate, LocalDate>> targets){
      AbstractMap.SimpleEntry<LocalDate, LocalDate> pair = get();
      return targets.stream().filter(e->e.getKey().compareTo(pair.getValue()) <= 0 && e.getValue().compareTo(pair.getKey()) >= 0)
      .map(e->new AbstractMap.SimpleEntry<LocalDate, LocalDate>(
            pair.getKey().compareTo(e.getKey()) <= 0 && e.getKey().compareTo(pair.getValue()) <= 0 ? e.getKey() : pair.getKey()
            , pair.getKey().compareTo(e.getValue()) <= 0 && e.getValue().compareTo(pair.getValue()) <= 0 ? e.getValue() : pair.getValue()))
      .collect(Collectors.toList());
   }

   /**
    * 非重複期間リストを抽出.
    * @param start 検査対象開始日
    * @param end 検査対象終了日
    * @return 重複でない期間を List で抽出
    */
   public default List<AbstractMap.SimpleEntry<LocalDate, LocalDate>> unbookPairs(LocalDate start, LocalDate end){
      List<AbstractMap.SimpleEntry<LocalDate, LocalDate>> list = new ArrayList<>();
      AbstractMap.SimpleEntry<LocalDate, LocalDate> pair = get();
      if (start.compareTo(pair.getValue()) <= 0 && end.compareTo(pair.getKey()) >= 0){
         if (start.compareTo(pair.getKey()) < 0){
            list.add(new SimpleEntry<LocalDate, LocalDate>(start, pair.getKey().minusDays(1)));
         }
         if (pair.getValue().compareTo(end) < 0){
            list.add(new SimpleEntry<LocalDate, LocalDate>(pair.getValue().plusDays(1), end));
         }
      }else{
         list.add(new SimpleEntry<>(start, end));
      }
      return list;
   }

   /**
    * 期間リスト→非重複期間リストの抽出.
    * @param targets 検査対象になる開始日と終了日の期間ペアのリスト
    * @return 重複でない期間のリスト
    */
   public default List<SimpleEntry<LocalDate, LocalDate>> unbookPairs(List<SimpleEntry<LocalDate, LocalDate>> targets){
      List<AbstractMap.SimpleEntry<LocalDate, LocalDate>> list = new ArrayList<>();
      AbstractMap.SimpleEntry<LocalDate, LocalDate> pair = get();
      targets.stream().forEach(e->{
         if (e.getKey().compareTo(pair.getValue()) <= 0 && e.getValue().compareTo(pair.getKey()) >= 0){
            if (e.getKey().compareTo(pair.getKey()) < 0){
               list.add(new SimpleEntry<LocalDate, LocalDate>(e.getKey(), pair.getKey().minusDays(1)));
            }
            if (pair.getValue().compareTo(e.getValue()) < 0){
               list.add(new SimpleEntry<LocalDate, LocalDate>(pair.getValue().plusDays(1), e.getValue()));
            }
         }else{
            list.add(new SimpleEntry<>(e.getKey(), e.getValue()));
         }
      });
      return list;
   }

   public default LocalDate start(){
      return get().getKey();
   }
   public default LocalDate end(){
      return get().getValue();
   }
}