Перекрытие диапазона дат с обнуляемыми датами - PullRequest
5 голосов
/ 07 июля 2010

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

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

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

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

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

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

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

Ответы [ 4 ]

12 голосов
/ 07 июля 2010

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

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

В этом случае, если вы хотите, чтобы нулевая дата представляла «отсутствие начальной / конечной границы», условия изменяются. Например, для 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)

Постоянно

Тогда перекрытие существует, если ни A, ни B не верны

Overlap := !(CondA || CondB)

и

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

Не (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. В большинстве языков, с которыми я знаком, это условие ошибки.

0 голосов
/ 09 февраля 2018

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

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

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

Или нулевые операторы в стиле C # 4.x:

(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. Поэтому измените это выражение так, чтобы вместо сравнения нулевого значения с EndB, когда StartA равно null, сравнивайте EndB с самим собой. Независимо от того, что такое EndB, выражение <code>EndB <= EndB будет истинным. (Мы могли бы создать переменные для представления BOT и EOT, но это проще).

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

0 голосов
/ 08 июля 2010

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

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;
                }
            }
0 голосов
/ 07 июля 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...