Ограничение диапазона дат с нулевыми датами

Я ищу расширенный ответ на вопрос, заданный здесь:

Определите, перекрываются ли два диапазона дат

где любая из дат в любом диапазоне дат может быть нулевой. Я придумал следующее решение, но я не уверен, что его можно упростить далее.

(StartA == NULL || StartA <= EndB) &&
(EndA == NULL || EndA >= StartB) &&
(StartB == NULL || StartB <= EndA) &&
(EndB == NULL || EndB >= StartA)

Предполагая:

Диапазоны DateTime от StartA до EndA и StartB до EndB

РЕДАКТИРОВАТЬ: Извините, что я быстро переместил вышеприведенную логику, которая, похоже, терпит неудачу, когда даты начала и окончания диапазона равны NULL. См. Решение David ниже для лучшего и хорошо объясненного подхода.

Ответ 1

Этот случай может быть обработан небольшим обобщением замечательного ответа Шарля Бретаны на этот вопрос.

Пусть CondA Mean DateRange полностью после DateRange B (True, если StartA > EndB) Пусть CondB Mean DateRange A полностью перед DateRange B (True, если EndA < StartB)

В этом случае, если вы хотите, чтобы нулевая дата представляла "никакую начальную/конечную границу", условия изменяются. Например, для CondA, чтобы DateRange A был полностью после DateRange B, DateRange A должен иметь определенное время начала, DateRange B должен иметь определенное конечное время, а время начала A должно быть после окончания времени окончания B:

CondA := (StartA != null) && (EndB != null) && (StartA > EndB)

CondB совпадает с включенным A и B:

CondB := (StartB != null) && (EndA != null) && (StartB > EndA)

Продолжение,

Затем Overlap существует, если ни A Nor B истинно

Overlap := !(CondA || CondB)

и

Теперь закон deMorgan, я думаю, говорит, что

Не (A или B) <= > Не A, а не B

Overlap == !CondA && !CondB
        == ![(StartA != null) && (EndB != null) && (StartA > EndB)] &&
           ![(StartB != null) && (EndA != null) && (StartB > EndA)]
        == [(StartA == null) || (EndB == null) || (StartA <= EndB)] &&
           [(StartB == null) || (EndA == null) || (StartB <= EndA)]

Я думаю, что это на самом деле немного более надежное, чем решение, которое вы разработали, потому что если EndB == NULL, но StartA не является нулевым, ваше первое условие приведет к сравнению StartA <= NULL. На большинстве языков, с которыми я знаком, это условие ошибки.

Ответ 2

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

Вероятно, не стоит этого упрощать, так как этот блок заканчивается примерно 8 операциями в худшем случае (4 в среднем благодаря оценке короткого замыкания).

Ответ 3

Все ответы основаны, если условие истинно. Здесь я хотел бы добавить примечание.

1- Тип переменной DateTime - это структура, и вы не можете установить ее в null, если только вы не используете тип с нулевым значением, например "DateTime?"

2- Чтобы найти диапазон перекрытия, выполните следующие шаги.

DateTime? StartOverLap = null,EndOverLap = null;
            if (StartA != null && StartB != null)
            {
                StartOverLap = StartA > StartB ? StartA : StartB;
            }
            else if (StartA == null && StartB != null)
            {
                StartOverLap = StartB;
            }
            else if (StartA != null && StartB == null)
            {
                StartOverLap = StartA;
            }
            if (EndA != null && EndB != null)
            {
                EndOverLap = EndA < EndB ? EndA : EndB;
            }
            else if (EndA == null && EndB != null)
            {
                EndOverLap = EndB;
            }
            else if (EndA != null && EndB == null)
            {
                EndOverLap = EndA;
            }
            if (StartOverLap != null && EndOverLap == null)
            {
                if (EndOverLap < StartOverLap)
                {
                    StartOverLap = null;
                    EndOverLap = null;
                }
            }

Ответ 4

Без учета нулей ответ

(StartA <= EndB) and (EndA >= StartB)(подробнее см.

с учетом нулей для дат начала и окончания,
Использование синтаксиса оператора C Ternary:
 (StartA != null? StartA: EndB <= EndB != null? EndB: StartA) && (EndA != null? EndA: StartB >= StartB != null? StartB: EndA)

Или операторы с нулевым стилем типа С#:

(StartA??EndB <= EndB??StartA) && (EndA??StartB >= StartB??EndA)

или в SQL:

(Coalesce(StartA, EndB) <= Coalesce(EndB, StartA)) And (Coalesce(EndA, StartB ) <= Coalesce(StartB , EndA))

Объяснение:
рассмотрите непустой ответ:
(StartA <= EndB) and (EndA >= StartB)

Теперь рассмотрим, что StartA имеет значение null, указывая, что диапазон дат A существует с начала времени (BOT). В этом случае DateRangeB никогда не может быть до DateRangeA. Поэтому первое условие (StartA (BOT) <= EndB) ВСЕГДА будет истинным, независимо от того, что такое EndB. Поэтому измените это выражение так, чтобы вместо сравнения null с EndB, когда StartA имеет значение null, сравните EndB с самим собой Независимо от того, что такое EndB, выражение EndB <= EndB будет истинным. (Мы могли бы создавать переменные для представления BOT и EOT, но это проще).

Сделайте то же самое для других трех входных переменных.