きり丸の技術日記

技術検証したり、資格等をここに残していきます。

Javaで期間と期間を比較して重複チェックする

よくある内容の記事ですので、特別な内容はありません。私が迷わないようにするための記事です。


日付と日付を比較することは簡単ですが、日付の開始日と終了日をまとめた期間と期間を比較して、重複があることをチェックするのはたいへんです。なお、次の式を満たせれば重複していることのチェックができます。誤りやすいので、テストはコピー&ペーストでもいいので書きましょう。

基準.開始日 <= 対象.終了日 && 対象.開始日 <= 基準.終了日
# 対象日を含むかどうかは、仕様に寄ります

環境

  • Java
    • 17

対象

期間クラスを作成し、重複確認メソッドを作成する。

※recordを使用しているので、読み方に慣れていない人はGitHubのコードを読んでください。

public record Term(LocalDate start, LocalDate end) { 

  // 基準.開始 <= 対象.終了 && 対象.開始 <= 基準.終了
  public boolean isOverlap(@NonNull Term param) {
    return !start.isAfter(param.end()) && !param.start().isAfter(end);
  }
}

テストクラスで重複をチェックします。テスト対象については次の項目をテストします。

  1. 部分的に重複している場合は、true
    1. 同日も含む
  2. 片方の期間に完全に包含している場合は、true
  3. 部分的にも期間が重複していない場合は、false

テストデータ

基準

開始日 終了日
2022/7/1 2022/10/31

比較

重複パターン

開始日 終了日
2022/4/1 2022/7/31
2022/8/1 2022/9/30
2022/10/1 2022/12/31
2022/6/1 2022/11/30
2022/10/31 2022/11/30

重複しないパターン

開始日 終了日
2022/2/1 2022/5/31
2022/12/1 2022/12/31

テストコード

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Nested
class isOverlap {

  Term base = new Term(
      LocalDate.of(2022, 7, 1),
      LocalDate.of(2022, 10, 31)
  );

  @MethodSource(value = "param")
  @ParameterizedTest
  public void test(LocalDate start, LocalDate end, boolean expected) {
    assertThat(base.isOverlap(new Term(start, end))).isEqualTo(expected);
  }

  public Stream<Arguments> param() {
    return Stream.of(
        Arguments.of(LocalDate.of(2022, 4, 1), LocalDate.of(2022, 7, 31), true),
        Arguments.of(LocalDate.of(2022, 8, 1), LocalDate.of(2022, 9, 30), true),
        Arguments.of(LocalDate.of(2022, 10, 1), LocalDate.of(2022, 12, 31), true),
        Arguments.of(LocalDate.of(2022, 6, 1), LocalDate.of(2022, 11, 30), true),
        Arguments.of(LocalDate.of(2022, 10, 31), LocalDate.of(2022, 11, 30), true),
        Arguments.of(LocalDate.of(2022, 2, 1), LocalDate.of(2022, 5, 31), false),
        Arguments.of(LocalDate.of(2022, 12, 1), LocalDate.of(2022, 12, 31), false)
    );
  }
}

備考

「基準.開始 <= 対象.終了 && 対象.開始 <= 基準.終了」の理解が難しいときは、図式しながら満たすことを確認すると分かりやすいと思います。

4つの項目の関係性を比較する関係上、私は混乱するのでよく図式しています。

ソースコード

終わりに

完全に自分用の記事です。

そこまで多発する概念ではないのですが、考え方を抑えておかないとあまり納得ができないので、理解のための図式があるだけでも私は満足です。

式だけ書かれていても、本当にそれで正しいかがピンとこないので、頑張って理解するのは大事です。

参考情報