Учитывая два диапазона дат, какой самый простой или эффективный способ определить, перекрываются ли два диапазона дат?
В качестве примера предположим, что мы имеем диапазоны , обозначаемые DateTime переменных StartDate1
в EndDate1
и StartDate2
к EndDate2
.
datetime
math
language-agnostic
Ян Нельсон
источник
источник
Ответы:
(StartA <= EndB) и (EndA> = StartB)
Доказательство:
пусть ConditionA означает, что DateRange A полностью после DateRange B
_ |---- DateRange A ------| |---Date Range B -----| _
(True, если
StartA > EndB
)Пусть ConditionB означает, что DateRange A полностью перед DateRange B
|---- DateRange A -----| _ _ |---Date Range B ----|
(True, если
EndA < StartB
)Тогда перекрытие существует, если ни A, ни B не верны -
(если один диапазон не полностью ни за другим,
ни полностью перед другим, тогда они должны перекрываться.)
Теперь один из законов де Моргана гласит:
Not (A Or B)
<=>Not A And Not B
Что переводится как:
(StartA <= EndB) and (EndA >= StartB)
ПРИМЕЧАНИЕ. Это включает условия, когда края точно перекрываются. Если вы хотите исключить , что
изменения
>=
операторов>
, и<=
к<
ЗАМЕТКА 2. Благодаря @Baodad см этот блог , фактическое перекрытие меньше:
{
endA-startA
,endA - startB
,endB-startA
,endB - startB
}(StartA <= EndB) and (EndA >= StartB)
(StartA <= EndB) and (StartB <= EndA)
ЗАМЕТКА 3. Благодаря @tomosius, более короткая версия гласит:
DateRangesOverlap = max(start1, start2) < min(end1, end2)
Это на самом деле синтаксический ярлык для более длинной реализации, который включает в себя дополнительные проверки, чтобы убедиться, что даты начала находятся в или до endDates. Получив это сверху:
Если даты начала и окончания могут быть не в порядке, т. Е. Если возможно, что
startA > endA
илиstartB > endB
, то вы также должны проверить, что они в порядке, что означает, что вы должны добавить два дополнительных правила действия:(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB)
или:(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB)
или,(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB))
или:(Max(StartA, StartB) <= Min(EndA, EndB)
Но чтобы реализовать
Min()
иMax()
, вы должны кодировать (используя троичную C для краткости):(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)
источник
Start
иEnd
значат слова . Если у вас есть две переменные с именем Top и Bottom, или East and West, или HighValue и LoValue, можно предположить или подразумевать, что что-то или кто-то где-то должен гарантировать, что одна из пар значений не будет сохранена в противоположных переменных. Только одна из двух пар, потому что, ну, это также будет работать, если обе пары значений переключаются.start
иend
(с семантикой, что «null start» = «С начала времени» и «null end» = «До конца времени»), вот так:(startA === null || endB === null || startA <= endB) && (endA === null || startB === null || endA >= startB)
DateRangesOverlap = max(start1, start2) < min(end1, end2)
Я считаю, что достаточно сказать, что два диапазона перекрываются, если:
источник
(StartDate1 <= EndDate2) and (EndDate1 >= StartDate2)
обозначение легче понять, Range1 всегда слева в тестах.<=
на,<
если начало включено, а конец - эксклюзив.В этой статье Библиотека периодов времени для .NET описывает отношение двух периодов времени перечислением PeriodRelation :
источник
Для рассуждений о временных отношениях (или любых других интервальных отношениях, приходите к этому), рассмотрим Интервальную Алгебру Аллена . Он описывает 13 возможных отношений, которые могут иметь два интервала по отношению друг к другу. Вы можете найти другие ссылки - «Аллен Интервал», кажется, оперативный поисковый термин. Вы также можете найти информацию об этих операциях в Сноуграссе « Разработка ориентированных на время приложений в SQL» (PDF можно найти в Интернете по адресу URL), а также в «Дата, Дарвен и Лоренцо», « Временные данные и реляционная модель» (2002) или « Время и реляционная теория: временные базы данных» в реляционная модель и SQL (2014; фактически второе издание TD & RM).
Короткий (МОГ) Ответ: даны два интервала дат ,
A
иB
с компонентами.start
и.end
и ограничения.start <= .end
, а затем два интервала перекрываются , если:Вы можете настроить использование
>=
против>
и<=
против,<
чтобы удовлетворить ваши требования к степени перекрытия.ErikE комментирует:
Я думаю, что вы не можете сосчитать две записи «до: до» и «после: после». Я мог бы увидеть 7 записей, если вы приравниваете некоторые отношения к их инверсиям (см. Диаграмму в ссылочном URL-адресе Википедии; в ней 7 записей, 6 из которых имеют разные обратные значения, а равные не имеют четких обратных). И разумно ли три, зависит от ваших требований.
источник
Если необходимо также рассчитать само перекрытие, вы можете использовать следующую формулу:
источник
Все решения, которые проверяют множество условий на основе расположения диапазонов по отношению друг к другу, можно значительно упростить, просто обеспечив ранний запуск определенного диапазона! Вы гарантируете, что первый диапазон начинается раньше (или в то же время), меняя диапазоны, если это необходимо, заранее.
Затем вы можете обнаружить перекрытие, если начало другого диапазона меньше или равно первому концу диапазона (если диапазоны включительно, содержат время начала и окончания) или меньше (если диапазоны включают начало и исключение конца) ,
Предполагая, что включительно с обоих концов, есть только четыре возможности, одна из которых не перекрывается:
Конечная точка диапазона 2 не входит в него. Итак, в псевдокоде:
Это может быть упрощено еще больше в:
Если диапазоны включают в начале , так и эксклюзивные в конце концов, вы просто должны заменить
>
с>=
во второмif
заявлении (для первого сегмента кода: во втором сегменте кода, вы бы использовать<
вместо<=
):Вы значительно ограничиваете количество проверок, которые вам нужно сделать, потому что вы удаляете половину проблемного пространства раньше, гарантируя, что диапазон 1 никогда не начинается после диапазона 2.
источник
Вот еще одно решение с использованием JavaScript. Особенности моего решения:
Тесты основаны на целых числах, но поскольку объекты даты в JavaScript сравнимы, вы можете просто добавить два объекта даты. Или вы можете добавить миллисекундную метку времени.
Код:
тесты:
Результат при беге с кармой, жасмином и фантомом:
источник
я бы сделал
Где
IsBetween
что то типаисточник
Вот код, который делает волшебство:
Куда..
Доказательство? Посмотрите эту суть кода тестовой консоли .
источник
Вот мое решение на Java , которое работает и на неограниченных интервалах
источник
!startA.after(endB)
означает startA <= endB и!endA.before(startB)
означает startB <= endA. Это критерии для закрытого интервала, а не открытого интервала.endB == null
иstartA == null
проверка на открытый интервал.endB == null
,startA == null
,endA == null
ИstartB == null
все критерии для проверки на неограниченный интервал , а не открытый интервал. Пример различий между неограниченными и открытыми интервалами: (10, 20) и (20, ноль) - два открытых интервала, которые не перекрываются. Последний действительно имеет неограниченный конец. Ваша функция вернет true, но интервалы не перекрываются, потому что интервалы не включают 20. (для простоты использовались числа вместо временных меток)Размещенное здесь решение не работает для всех перекрывающихся диапазонов ...
мое рабочее решение было:
источник
Это было мое решение javascript с помощью moment.js:
источник
Простой способ запомнить решение будет
min(ends)>max(starts)
источник
В Microsoft SQL SERVER - функция SQL
источник
Самый простой способ - использовать специально разработанную специализированную библиотеку для работы с датой и временем.
java.time & ThreeTen-Extra
Лучшим в бизнесе является
java.time
фреймворк, встроенный в Java 8 и более поздние версии . Добавьте к этому проект ThreeTen-Extra, который дополняет java.time дополнительными классами, в частностиInterval
классом, который нам нужен здесь.Что касается
language-agnostic
тега в этом Вопросе, исходный код для обоих проектов доступен для использования на других языках (обратите внимание на их лицензии).Interval
org.threeten.extra.Interval
Класс удобен, но требует дат времени моментов (java.time.Instant
объекты) , а не даты только значение. Итак, мы используем первый момент дня в UTC для представления даты.Создайте,
Interval
чтобы представить этот промежуток времени.Мы также можем определить
Interval
начальный момент плюс аDuration
.Сравнение с тестом на совпадения легко.
Вы можете сравнить
Interval
с другимInterval
илиInstant
:abuts
contains
encloses
equals
isAfter
isBefore
overlaps
Все они используют
Half-Open
подход к определению промежутка времени, когда начало включительно, а окончание - исключительно .источник
Это продолжение превосходного ответа @ charles-bretana.
Ответ, однако, не делает различий между открытым, закрытым и полуоткрытым (или полузакрытым) интервалами.
Случай 1 : A, B - закрытые интервалы
Перекрываются, если:
(StartA <= EndB) and (EndA >= StartB)
Случай 2 : A, B - открытые интервалы
Перекрываются, если:
(StartA < EndB) and (EndA > StartB)
Дело 3 : A, B прямо открыто
Условие перекрытия:
(StartA < EndB) and (EndA > StartB)
Дело 4 : A, B оставлено открытым
Условие перекрытия:
(StartA < EndB) and (EndA > StartB)
Случай 5 : Право открыто, Б закрыто
Условие перекрытия:
(StartA <= EndB) and (EndA > StartB)
так далее...
Наконец, общее условие перекрытия двух интервалов
(StartA <🞐 EndB) и (EndA> 🞐 StartB)
где 🞐 превращает строгое неравенство в нестрогое всякий раз, когда проводится сравнение между двумя включенными конечными точками.
источник
Краткий ответ с использованием моментов :
ответ основан на ответах выше, но его сокращают.
источник
Если вы используете диапазон дат, который еще не закончился (все еще продолжается), например, не установлен endDate = '0000-00-00', вы не можете использовать BETWEEN, потому что 0000-00-00 не является действительной датой!
Я использовал это решение:
Если startdate2 выше, тогда enddate не перекрывается!
источник
Для меня ответ слишком прост, поэтому я создал более общий динамический оператор SQL, который проверяет, есть ли у человека перекрывающиеся даты.
источник
Математическое решение, данное @Bretana, хорошо, но игнорирует две конкретные детали:
О закрытом или открытом состоянии интервальных границ, решение @Bretana справедливо для замкнутых интервалов
может быть переписан для полуоткрытых интервалов, чтобы:
Это исправление необходимо, поскольку граница открытого интервала по определению не принадлежит диапазону значений интервала.
А насчет пустых интервалов , ну, здесь показанные выше отношения НЕ имеют места. Пустые интервалы, которые не содержат никаких допустимых значений по определению, должны обрабатываться как особый случай. Я демонстрирую это своей библиотекой времени Java Time4J на следующем примере:
Первая квадратная скобка «[» обозначает закрытое начало, в то время как последняя квадратная скобка «)» обозначает открытый конец.
Как показано выше, пустые интервалы нарушают условие перекрытия выше (особенно startA <endB), поэтому Time4J (и другие библиотеки тоже) должны обрабатывать его как специальный крайний случай, чтобы гарантировать перекрытие любого произвольного интервала с пустым интервалом не существует. Конечно, интервалы дат (которые по умолчанию закрыты в Time4J, но могут быть и полуоткрытыми, как пустые интервалы дат) обрабатываются аналогичным образом.
источник
Вот универсальный метод, который может быть полезным локально.
источник
источник
Используя Java util.Date, вот что я сделал.
источник
По моему мнению, самый простой способ сделать это - сравнить EndDate1 с StartDate2 и EndDate2 с StartDate1.
Это, конечно, если вы рассматриваете интервалы, когда StartDate всегда предшествует EndDate.
источник
У меня была ситуация, когда у нас были даты, а не даты, и даты могли перекрываться только в начале / конце. Пример ниже:
(Зеленый - текущий интервал, синие блоки - допустимые интервалы, красные - перекрывающиеся).
Я адаптировал ответ Яна Нельсона к следующему решению:
Это соответствует всем случаям перекрытия, но игнорирует разрешенные случаи перекрытия.
источник
Отделить проблему в случаях затем обрабатывать каждый случай .
Ситуация «пересечение двух диапазонов дат» охватывается двумя случаями: первый диапазон дат начинается во втором, или второй диапазон дат начинается в первом.
источник
Вы можете попробовать это:
источник
Это было мое решение, оно возвращает истину, когда значения не перекрываются:
X START 1 Y END 1
НАЧАЛО 2 B КОНЕЦ 2
источник
Для рубина я также нашел это:
Нашел это здесь с хорошим объяснением -> http://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-ruby-or-rails
источник
Приведенный ниже запрос дает мне идентификаторы, для которых предоставленный диапазон дат (даты начала и окончания перекрывается с любой из дат (даты начала и окончания) в моем имени таблицы
источник