Как проверить, не перекрывает ли один период даты другой период даты

Итак, у меня есть созданная мной функция под названием isDateOverlapping. Он принимает (всех типов LocalDate):

  • Дата начала 1
  • Дата окончания 1
  • Дата начала 2
  • Дата окончания 2

Эта функция сообщает мне, перекрываются ли 2 периода даты или нет.

Например, если у меня есть 1 период с 2019-06-15 to 2019-06-18 и другой период с 2019-06-15 to 2019-06-12. Он вернет истину, потому что 2 периода даты перекрываются.

Однако моя функция, похоже, не всегда возвращает правильный ответ. Не могли бы вы помочь.

public boolean isDateOverlapping(LocalDate start1, LocalDate end1, LocalDate start2, LocalDate end2) {

    if (start1.isAfter(start2) && start2.isBefore(start1)) {
        return true;

    } else if (end1.isBefore(end2) && start1.isAfter(start2)) {
        return true;
    } else if (start1.isAfter(end1) && end2.isBefore(start2)) {
        return true;
    }

    return false;

}

person Joey Yue    schedule 24.06.2019    source источник
comment
Считаете ли вы, что период перекрывает другой, если последний день более раннего периода совпадает с первым днем ​​более позднего? Это своего рода крайний случай, который следует определить перед тем, как что-либо реализовывать.   -  person deHaar    schedule 24.06.2019
comment
другой период с 15.06.2019 по 12.06.2019 - значит, период может идти назад? Вы хотите, чтобы этот период рассматривался так же, как период с 12.06.2019 по 15.06.2019?   -  person Ole V.V.    schedule 24.06.2019
comment
Для особых случаев, таких как пустые интервалы и т. Д., См. Также мою запись   -  person Meno Hochschild    schedule 25.06.2019


Ответы (2)


Самый простой способ понять это - рассмотреть четыре возможности:

  1. второй интервал содержит первый интервал: s2 ‹s1‹ e1 ‹e2
  2. Второй интервал содержит начало первого интервала: s2 ​​‹s1‹ e2 ‹e1
  3. Второй интервал содержит конец первого интервала: s1 ‹s2‹ e1 ‹e2
  4. Второй интервал содержится в первом интервале: s1 ‹s2‹ e2 ‹e1

Их можно проиллюстрировать следующим образом:

        1.                  2.                    3.               4.

|---------------|       |-------|                |------|        |----|     Second Interval
     |-----|                 |------|        |-------|       |-----------|  First Interval
s2   s1    e1   e2      s2   s1 e2  e1      s1  s2   e1 e2   s1  s2  e2  e1

Общим инвариантом во всех этих 4 случаях является то, что второй интервал должен начинаться до того, как закончится первый интервал, а второй интервал должен заканчиваться после начала первого интервала.

Это дает вам:

public boolean isDateOverlapping(LocalDate start1, LocalDate end1, LocalDate start2, LocalDate end2) {
    return start2.isBefore(end1) && end2.isAfter(start1); 
}

Обратите внимание, что вам может потребоваться небольшое изменение, если вы хотите, чтобы ваш метод возвращал истину, когда интервалы перекрываются в одной точке. В этом случае вам нужно заменить start2.isBefore(end1) на !start2.isAfter(end1) и end2.isAfter(start1) на !end2.isBefore(start1).

Также обратите внимание, что я предполагаю start1 <= end1 и start2 <= end2. Если это не всегда так, вам также придется это проверить и при необходимости поменять местами startN на endN, прежде чем проверять вышеуказанные условия.

person Eran    schedule 24.06.2019
comment
Один вопрос, я думал, есть еще крайние случаи? Эта одна строка решает дела? - person Joey Yue; 24.06.2019
comment
@JoeyYue, пожалуйста, посмотрите мои правки - person Eran; 24.06.2019

Чтобы определить, перекрываются ли два периода даты только ниже, достаточно логики.

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)

person Diptesh    schedule 24.06.2019