(StartA & lt; = 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
)
Затем Overlap существует, если ни A Nor B не является истинным - ( Если один диапазон не является полностью ни за другим, ни полностью перед другим, то они должны перекрываться.)
Теперь один из законов Де Моргана говорит, что:
Not (A Or B)
& lt; => Not A And Not B
Что означает: (StartA <= EndB) and (EndA >= StartB)
ПРИМЕЧАНИЕ. Сюда входят условия, при которых края накладываются точно. Если вы хотите исключить это, измените операторы >=
на >
и <=
на <
NOTE2. Благодаря @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)
Это на самом деле синтаксический ярлык для более длинной реализации, который включает дополнительные проверки, чтобы проверить, что даты начала включены или до конца. Вывод этого сверху:
Если даты начала и окончания могут быть не в порядке, то есть, если возможно, что 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)
самый простой
Самый простой способ - использовать хорошо спроектированную выделенную библиотеку для работы с датой.
someInterval.overlaps( anotherInterval )
java.time & амп; ThreeTen-Extra
Лучшим в бизнесе является структура
java.time
, встроенная в Java 8 и более поздние версии. Добавьте к этому проект ThreeTen-Extra , который дополняет java.time дополнительными классами, в частности классомInterval
, который нам нужен здесь.Что касается тег
language-agnostic
в этом Вопросе, исходный код для обоих проектов доступен для использования на других языках (помните о своих лицензиях).
Interval
Класс
org.threeten.extra.Interval
удобен, но для него требуются моменты времени дат (java.time.Instant
), а не только значения даты , Поэтому мы переходим к использованию первого момента дня в UTC для представления даты.Instant start = Instant.parse( "2016-01-01T00:00:00Z" ); Instant stop = Instant.parse( "2016-02-01T00:00:00Z" );
Создайте
Interval
для представления этого промежутка времени.Interval interval_A = Interval.of( start , stop );
Мы также можем определить
Interval
с начальным моментом плюсDuration
.Instant start_B = Instant.parse( "2016-01-03T00:00:00Z" ); Interval interval_B = Interval.of( start_B , Duration.of( 3 , ChronoUnit.DAYS ) );
Сравнение с тестом на перекрытия очень просто.
Boolean overlaps = interval_A.overlaps( interval_B );
Вы можете сравнить
Interval
с другимInterval
илиInstant
:Все они используют подход
Half-Open
для определения промежутка времени, в котором начало включено , а окончание - exclusive .
Разделите проблему на случаи, затем обрабатывайте каждый случай.
Ситуация «два диапазона дат пересекаются» охватывает два случая: первый диапазон дат начинается во втором, или второй диапазон дат начинается с первый.
Самый простой способ сделать это, на мой взгляд, это сравнить, если либо EndDate1 до StartDate2 и EndDate2 до StartDate1.
Это, конечно, если вы рассматриваете интервалы, где StartDate всегда находится перед EndDate.
Я бы сделал
StartDate1.IsBetween(StartDate2, EndDate2) || EndDate1.IsBetween(StartDate2, EndDate2)
Где IsBetween
что-то вроде
public static bool IsBetween(this DateTime value, DateTime left, DateTime right) {
return (value > left && value < right) || (value < left && value > right);
}
Это было мое решение, оно возвращает true, когда значения не перекрываются:
X START 1 Y END 1
A START 2 B END 2
TEST1: (X <= A || X >= B)
&&
TEST2: (Y >= B || Y <= A)
&&
TEST3: (X >= B || Y <= A)
X-------------Y
A-----B
TEST1: TRUE
TEST2: TRUE
TEST3: FALSE
RESULT: FALSE
---------------------------------------
X---Y
A---B
TEST1: TRUE
TEST2: TRUE
TEST3: TRUE
RESULT: TRUE
---------------------------------------
X---Y
A---B
TEST1: TRUE
TEST2: TRUE
TEST3: TRUE
RESULT: TRUE
---------------------------------------
X----Y
A---------------B
TEST1: FALSE
TEST2: FALSE
TEST3: FALSE
RESULT: FALSE
Вы можете попробовать следующее:
//custom date for example
$d1 = new DateTime("2012-07-08");
$d2 = new DateTime("2012-07-11");
$d3 = new DateTime("2012-07-08");
$d4 = new DateTime("2012-07-15");
//create a date period object
$interval = new DateInterval('P1D');
$daterange = iterator_to_array(new DatePeriod($d1, $interval, $d2));
$daterange1 = iterator_to_array(new DatePeriod($d3, $interval, $d4));
array_map(function($v) use ($daterange1) { if(in_array($v, $daterange1)) print "Bingo!";}, $daterange);
У меня была ситуация, когда у нас были даты, а не даты, и даты могут перекрываться только с начала / конца. Пример ниже:
(зеленый - текущий интервал, синие блоки - это допустимые интервалы, красные - перекрывающиеся интервалы).
Я адаптировал ответ Яна Нельсона на следующее решение:
(startB <= startA && endB > startA)
|| (startB >= startA && startB < endA)
Это соответствует всем случаям перекрытия, но игнорирует разрешенные совпадения.
Это мое решение для javascript с помощью момента. js:
// Current row dates
var dateStart = moment("2014-08-01", "YYYY-MM-DD");
var dateEnd = moment("2014-08-30", "YYYY-MM-DD");
// Check with dates above
var rangeUsedStart = moment("2014-08-02", "YYYY-MM-DD");
var rangeUsedEnd = moment("2014-08-015", "YYYY-MM-DD");
// Range covers other ?
if((dateStart <= rangeUsedStart) && (rangeUsedEnd <= dateEnd)) {
return false;
}
// Range intersects with other start ?
if((dateStart <= rangeUsedStart) && (rangeUsedStart <= dateEnd)) {
return false;
}
// Range intersects with other end ?
if((dateStart <= rangeUsedEnd) && (rangeUsedEnd <= dateEnd)) {
return false;
}
// All good
return true;
Я считаю, что достаточно сказать, что два диапазона перекрываются, если:
(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
(StartDate1 <= EndDate2) and (EndDate1 >= StartDate2)
легче понять, Range1 всегда остается слева в тестах.
– A.L
2 December 2013 в 16:46
<=
на <
, если включение включено, а конец - исключительным.
– Richard Schneider
9 April 2014 в 03:54
Для рассуждений о временных соотношениях (или любых других интервальных соотношениях, приходим к этому), рассмотрим интервальную алгебру Аллена . Он описывает 13 возможных отношений, которые могут иметь два интервала относительно друг друга. Вы можете найти другие ссылки - «Аллен Интервал», похоже, является оперативным поисковым термином. Вы также можете найти информацию об этих операциях в разрабатываемых Time-Oriented приложениях Snodgrass в SQL (PDF доступен онлайн по URL-адресу), а в Date, Darwen и Lorentzos Временные данные и реляционная модель (2002) или Временная и реляционная теория: временные базы данных в реляционной модели и SQL (2014; эффективно второе издание TD & amp; RM).
short (ish) отвечает: заданы два интервала дат A
и B
с компонентами .start
и .end
и ограничение .start <= .end
, затем два интервала перекрываются, если:
A.end >= B.start AND A.start <= B.end
Вы можете настроить использование >=
vs >
и <=
vs <
, чтобы соответствовать вашим требованиям для степени перекрытия.
Комментарии ErikE:
Вы можете получить только 13, если посчитаете забавные вещи ... Я могу получить «15 возможных отношений, которые могут иметь два интервала», когда я схожу с ума. Разумным подсчетом, я получаю только шесть, и если вы выбрасываете заботу о том, стоит ли сначала A или B, я получаю только три (не пересекаюсь, частично пересекаюсь, один полностью внутри другого). 15 выполняется следующим образом: [before: before, start, inside, end, after], [start: start, inside, end, after], [внутри: внутри, после, после], [конец: конец, после], [ после того, как: после].
Я думаю, что вы не можете считать две записи «до: до» и «после: после». Я мог бы увидеть 7 записей, если вы приравняете некоторые отношения со своими обратными (см. Диаграмму в указанном URL-адресе Википедии, имеет 7 записей, 6 из которых имеют разные обратные значения, причем они не имеют четкого обратного). И то, насколько три разумны, зависит от ваших требований.
----------------------|-------A-------|---------------------- |----B1----| |----B2----| |----B3----| |----------B4----------| |----------------B5----------------| |----B6----| ----------------------|-------A-------|---------------------- |------B7-------| |----------B8-----------| |----B9----| |----B10-----| |--------B11--------| |----B12----| |----B13----| ----------------------|-------A-------|----------------------
Вот мое решение в Java , которое также работает на неограниченных интервалах
private Boolean overlap (Timestamp startA, Timestamp endA,
Timestamp startB, Timestamp endB)
{
return (endB == null || startA == null || !startA.after(endB))
&& (endA == null || startB == null || !endA.before(startB));
}
!startA.after(endB)
означает, что startA & lt; = endB и !endA.before(startB)
означает startB & lt; = endA. Это критерии для замкнутого интервала, а не открытого интервала.
– Henrik
4 October 2017 в 12:03
endB == null
и startA == null
, проверяют открытый интервал.
– Khaled.K
4 October 2017 в 14:32
endB == null
, startA == null
, endA == null
и startB == null
- все критерии проверки неограниченного интервала, а не открытого интервала. Пример различий между неограниченными и открытыми интервалами: (10, 20) и (20, null) - два открытых интервала, которые не перекрываются. Последний имеет неограниченный конец. Ваша функция вернет true, но интервалы не перекрываются, потому что интервалы не включают 20. (для простоты использовались цифры вместо временных меток)
– Henrik
4 October 2017 в 15:39
Для ruby я также нашел это:
class Interval < ActiveRecord::Base
validates_presence_of :start_date, :end_date
# Check if a given interval overlaps this interval
def overlaps?(other)
(start_date - other.end_date) * (other.start_date - end_date) >= 0
end
# Return a scope for all interval overlapping the given interval, including the given interval itself
named_scope :overlapping, lambda { |interval| {
:conditions => ["id <> ? AND (DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", interval.id, interval.end_date, interval.start_date]
}}
end
Нашел его здесь с приятным объяснением -> http://makandracards.com/makandra/984-test-if-two-date -ranges-перекрывание-в-рубина или рельсы [/ д2]
if (StartDate1 > StartDate2) swap(StartDate, EndDate);
(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1);
Математическое решение, данное @Bretana, является хорошим, но пренебрегает двумя конкретными деталями:
О закрытом или открытом состоянии интервальных границ, решение @Bretana, действительное для закрытых интервалов
(StartA & lt; = EndB) и (EndA> = StartB)
можно переписать для полуоткрытых интервалов:
(StartA & lt; EndB) и (EndA> StartB)
< / blockquote>Эта коррекция необходима, потому что граница открытого интервала по определению не относится к диапазону значений интервала.
И о пустых интервалах, ну, вот соотношение, показанное выше НЕ держится. Пустые интервалы, которые не содержат допустимого значения по определению, должны обрабатываться как особый случай. Я продемонстрирую это по моей библиотеке времени Java Time4J в этом примере:
MomentInterval a = MomentInterval.between(Instant.now(), Instant.now().plusSeconds(2)); MomentInterval b = a.collapse(); // make b an empty interval out of a System.out.println(a); // [2017-04-10T05:28:11,909000000Z/2017-04-10T05:28:13,909000000Z) System.out.println(b); // [2017-04-10T05:28:11,909000000Z/2017-04-10T05:28:11,909000000Z)
Ведущая квадратная скобка «[» означает закрытое начало, а последняя скобка «)» указывает на открытый конец.
System.out.println( "startA < endB: " + a.getStartAsInstant().isBefore(b.getEndAsInstant())); // false System.out.println( "endA > startB: " + a.getEndAsInstant().isAfter(b.getStartAsInstant())); // true System.out.println("a overlaps b: " + a.intersects(b)); // a overlaps b: false
Как показано выше, пустые интервалы нарушают вышеперечисленное условие перекрытия (особенно startA & lt; endB), поэтому Time4J (и другие библиотеки тоже) должны обрабатывать его как специальный фронт в чтобы гарантировать, что перекрытие любого произвольного интервала с пустым интервалом не существует. Конечно, интервалы дат (которые закрыты по умолчанию в Time4J, но могут быть полуоткрытыми, также как и пустые интервалы даты) обрабатываются аналогичным образом.
public static class NumberExtensionMethods
{
public static Boolean IsBetween(this Int64 value, Int64 Min, Int64 Max)
{
if (value >= Min && value <= Max) return true;
else return false;
}
public static Boolean IsBetween(this DateTime value, DateTime Min, DateTime Max)
{
Int64 numricValue = value.Ticks;
Int64 numericStartDate = Min.Ticks;
Int64 numericEndDate = Max.Ticks;
if (numricValue.IsBetween(numericStartDate, numericEndDate) )
{
return true;
}
return false;
}
}
public static Boolean IsOverlap(DateTime startDate1, DateTime endDate1, DateTime startDate2, DateTime endDate2)
{
Int64 numericStartDate1 = startDate1.Ticks;
Int64 numericEndDate1 = endDate1.Ticks;
Int64 numericStartDate2 = startDate2.Ticks;
Int64 numericEndDate2 = endDate2.Ticks;
if (numericStartDate2.IsBetween(numericStartDate1, numericEndDate1) ||
numericEndDate2.IsBetween(numericStartDate1, numericEndDate1) ||
numericStartDate1.IsBetween(numericStartDate2, numericEndDate2) ||
numericEndDate1.IsBetween(numericStartDate2, numericEndDate2))
{
return true;
}
return false;
}
if (IsOverlap(startdate1, enddate1, startdate2, enddate2))
{
Console.WriteLine("IsOverlap");
}
Решение, размещенное здесь, не работает для всех перекрывающихся диапазонов ...
----------------------|-------A-------|---------------------- |----B1----| |----B2----| |----B3----| |----------B4----------| |----------------B5----------------| |----B6----| ----------------------|-------A-------|---------------------- |------B7-------| |----------B8-----------| |----B9----| |----B10-----| |--------B11--------| |----B12----| |----B13----| ----------------------|-------A-------|----------------------
мое рабочее решение было:
AND ( ('start_date' BETWEEN STARTDATE AND ENDDATE) -- caters for inner and end date outer OR ('end_date' BETWEEN STARTDATE AND ENDDATE) -- caters for inner and start date outer OR (STARTDATE BETWEEN 'start_date' AND 'end_date') -- only one needed for outer range where dates are inside. )
Все решения, которые проверяют множество условий, основанных на том, где диапазоны находятся относительно друг друга, могут быть значительно упрощены , просто гарантируя, что определенный диапазон начинается раньше! Вы гарантируете, что первый диапазон запускается раньше (или в то же время) путем замены диапазонов, если это необходимо, спереди.
Затем вы можете обнаружить перекрытие, если другой пуск диапазона меньше или равен первому концу диапазона (если диапазоны включительно, включая как начальное, так и конечное время) или меньше (если диапазоны включают начало и исключение конца).
Предполагая, что на обоих концах включено все, существует только четыре возможности, overlap:
|----------------------| range 1
|---> range 2 overlap
|---> range 2 overlap
|---> range 2 overlap
|---> range 2 no overlap
Конечная точка диапазона 2 не входит в нее. Итак, в псевдокоде:
def doesOverlap (r1, r2):
if r1.s > r2.s:
swap r1, r2
if r2.s > r1.e:
return false
return true
Это может быть еще более упрощено:
def doesOverlap (r1, r2):
if r1.s > r2.s:
swap r1, r2
return r2.s <= r1.e
Если диапазоны включены в начале и в конце, вы должны просто замените >
на >=
во втором операторе if
(для первого сегмента кода: во втором сегменте кода вы должны использовать <
, а не <=
):
|----------------------| range 1
|---> range 2 overlap
|---> range 2 overlap
|---> range 2 no overlap
|---> range 2 no overlap
Вы сильно ограничиваете количество проверок, которые вы должны выполнить, потому что вы сначала удаляете половину проблемного пространства, гарантируя, что диапазон 1 никогда не запускается после диапазона 2.
В Microsoft SQL SERVER - функция SQL
CREATE FUNCTION IsOverlapDates
(
@startDate1 as datetime,
@endDate1 as datetime,
@startDate2 as datetime,
@endDate2 as datetime
)
RETURNS int
AS
BEGIN
DECLARE @Overlap as int
SET @Overlap = (SELECT CASE WHEN (
(@startDate1 BETWEEN @startDate2 AND @endDate2) -- caters for inner and end date outer
OR
(@endDate1 BETWEEN @startDate2 AND @endDate2) -- caters for inner and start date outer
OR
(@startDate2 BETWEEN @startDate1 AND @endDate1) -- only one needed for outer range where dates are inside.
) THEN 1 ELSE 0 END
)
RETURN @Overlap
END
GO
--Execution of the above code
DECLARE @startDate1 as datetime
DECLARE @endDate1 as datetime
DECLARE @startDate2 as datetime
DECLARE @endDate2 as datetime
DECLARE @Overlap as int
SET @startDate1 = '2014-06-01 01:00:00'
SET @endDate1 = '2014-06-01 02:00:00'
SET @startDate2 = '2014-06-01 01:00:00'
SET @endDate2 = '2014-06-01 01:30:00'
SET @Overlap = [dbo].[IsOverlapDates] (@startDate1, @endDate1, @startDate2, @endDate2)
SELECT Overlap = @Overlap
Вот код, который делает магию:
var isOverlapping = ((A == null || D == null || A <= D)
&& (C == null || B == null || C <= B)
&& (A == null || B == null || A <= B)
&& (C == null || D == null || C <= D));
Где ..
Доказательство? Проверьте этот тест gist .
Использование Java util.Date, вот что я сделал.
public static boolean checkTimeOverlaps(Date startDate1, Date endDate1, Date startDate2, Date endDate2)
{
if (startDate1 == null || endDate1 == null || startDate2 == null || endDate2 == null)
return false;
if ((startDate1.getTime() <= endDate2.getTime()) && (startDate2.getTime() <= endDate1.getTime()))
return true;
return false;
}
Ниже запроса отображаются идентификаторы, для которых заданный диапазон дат (даты начала и окончания совпадают с любой датой (датой начала и окончания) в моей таблице_name
select id from table_name where (START_DT_TM >= 'END_DATE_TIME' OR
(END_DT_TM BETWEEN 'START_DATE_TIME' AND 'END_DATE_TIME'))
Вот общий метод, который может быть полезен локально.
// Takes a list and returns all records that have overlapping time ranges.
public static IEnumerable<T> GetOverlappedTimes<T>(IEnumerable<T> list, Func<T, bool> filter, Func<T,DateTime> start, Func<T, DateTime> end)
{
// Selects all records that match filter() on left side and returns all records on right side that overlap.
var overlap = from t1 in list
where filter(t1)
from t2 in list
where !object.Equals(t1, t2) // Don't match the same record on right side.
let in1 = start(t1)
let out1 = end(t1)
let in2 = start(t2)
let out2 = end(t2)
where in1 <= out2 && out1 >= in2
let totover = GetMins(in1, out1, in2, out2)
select t2;
return overlap;
}
public static void TestOverlap()
{
var tl1 = new TempTimeEntry() { ID = 1, Name = "Bill", In = "1/1/08 1:00pm".ToDate(), Out = "1/1/08 4:00pm".ToDate() };
var tl2 = new TempTimeEntry() { ID = 2, Name = "John", In = "1/1/08 5:00pm".ToDate(), Out = "1/1/08 6:00pm".ToDate() };
var tl3 = new TempTimeEntry() { ID = 3, Name = "Lisa", In = "1/1/08 7:00pm".ToDate(), Out = "1/1/08 9:00pm".ToDate() };
var tl4 = new TempTimeEntry() { ID = 4, Name = "Joe", In = "1/1/08 3:00pm".ToDate(), Out = "1/1/08 8:00pm".ToDate() };
var tl5 = new TempTimeEntry() { ID = 1, Name = "Bill", In = "1/1/08 8:01pm".ToDate(), Out = "1/1/08 8:00pm".ToDate() };
var list = new List<TempTimeEntry>() { tl1, tl2, tl3, tl4, tl5 };
var overlap = GetOverlappedTimes(list, (TempTimeEntry t1)=>t1.ID==1, (TempTimeEntry tIn) => tIn.In, (TempTimeEntry tOut) => tOut.Out);
Console.WriteLine("\nRecords overlap:");
foreach (var tl in overlap)
Console.WriteLine("Name:{0} T1In:{1} T1Out:{2}", tl.Name, tl.In, tl.Out);
Console.WriteLine("Done");
/* Output:
Records overlap:
Name:Joe T1In:1/1/2008 3:00:00 PM T1Out:1/1/2008 8:00:00 PM
Name:Lisa T1In:1/1/2008 7:00:00 PM T1Out:1/1/2008 9:00:00 PM
Done
*/
}
Я знаю, что это было отмечено как язык-агностик, но для всех вас, внедряющихся в Java: не изобретайте велосипед и не используйте Joda Time.
Ответ слишком прост для меня, поэтому я создал более общий динамический оператор SQL, который проверяет, имеет ли человек какие-либо перекрывающиеся даты.
SELECT DISTINCT T1.EmpID
FROM Table1 T1
INNER JOIN Table2 T2 ON T1.EmpID = T2.EmpID
AND T1.JobID <> T2.JobID
AND (
(T1.DateFrom >= T2.DateFrom AND T1.dateFrom <= T2.DateTo)
OR (T1.DateTo >= T2.DateFrom AND T1.DateTo <= T2.DateTo)
OR (T1.DateFrom < T2.DateFrom AND T1.DateTo IS NULL)
)
AND NOT (T1.DateFrom = T2.DateFrom)
Это расширение к отличному ответу by @ charles-bretana.
. Однако ответ не делает различия между открытыми, закрытыми и полуоткрытыми (или полузакрытые) интервалы.
Случай 1: A, B - замкнутые интервалы
A = [StartA, EndA]
B = [StartB, EndB]
[---- DateRange A ------] (True if StartA > EndB)
[--- Date Range B -----]
[---- DateRange A -----] (True if EndA < StartB)
[--- Date Range B ----]
Перекрытие iff: (StartA <= EndB) and (EndA >= StartB)
Случай 2: A, B - открытые интервалы
A = (StartA, EndA)
B = (StartB, EndB)
(---- DateRange A ------) (True if StartA >= EndB)
(--- Date Range B -----)
(---- DateRange A -----) (True if EndA <= StartB)
(--- Date Range B ----)
Перекрытие iff: (StartA < EndB) and (EndA > StartB)
Случай 3: A, B правое открытие
A = [StartA, EndA)
B = [StartB, EndB)
[---- DateRange A ------) (True if StartA >= EndB)
[--- Date Range B -----)
[---- DateRange A -----) (True if EndA <= StartB)
[--- Date Range B ----)
Условие перекрытия: (StartA < EndB) and (EndA > StartB)
Случай 4: A, B влево открыта
A = (StartA, EndA]
B = (StartB, EndB]
(---- DateRange A ------] (True if StartA >= EndB)
(--- Date Range B -----]
(---- DateRange A -----] (True if EndA <= StartB)
(--- Date Range B ----]
Условие перекрытия: (StartA < EndB) and (EndA > StartB)
Случай 5: правый открытый, B закрыт
A = [StartA, EndA)
B = [StartB, EndB]
[---- DateRange A ------) (True if StartA > EndB)
[--- Date Range B -----]
[---- DateRange A -----) (True if EndA <= StartB)
[--- Date Range B ----]
Условие перекрытия: (StartA <= EndB) and (EndA > StartB)
и т. д.
Наконец, общее условие для перекрытия двух интервалов -
(StartA & lt; EndB) и (EndA>
Если необходимо также рассчитать перекрытие, вы можете использовать следующую формулу:
overlap = max(0, min(EndDate1, EndDate2) - max(StartDate1, StartDate2))
if (overlap > 0) {
...
}
Если вы используете диапазон дат, который еще не закончился (все еще продолжается), например. не установлен endDate = '0000-00-00', вы не можете использовать BETWEEN, потому что 0000-00-00 не является допустимой датой!
Я использовал это решение:
(Startdate BETWEEN '".$startdate2."' AND '".$enddate2."') //overlap: starts between start2/end2
OR (Startdate < '".$startdate2."'
AND (enddate = '0000-00-00' OR enddate >= '".$startdate2."')
) //overlap: starts before start2 and enddate not set 0000-00-00 (still on going) or if enddate is set but higher then startdate2
Если startdate2 выше, то enddate нет перекрытия!
Вот еще одно решение с использованием JavaScript. Специальности моего решения:
Тесты основаны на целых числах, но поскольку объекты даты в JavaScript сопоставимы, вы можете просто выбросить два объекта даты.
/**
* Compares to comparable objects to find out whether they overlap.
* It is assumed that the interval is in the format [from,to) (read: from is inclusive, to is exclusive).
* A null value is interpreted as infinity
*/
function intervalsOverlap(from1, to1, from2, to2) {
return (to2 === null || from1 < to2) && (to1 === null || to1 > from2);
}
describe('', function() {
function generateTest(firstRange, secondRange, expected) {
it(JSON.stringify(firstRange) + ' and ' + JSON.stringify(secondRange), function() {
expect(intervalsOverlap(firstRange[0], firstRange[1], secondRange[0], secondRange[1])).toBe(expected);
});
}
describe('no overlap (touching ends)', function() {
generateTest([10,20], [20,30], false);
generateTest([20,30], [10,20], false);
generateTest([10,20], [20,null], false);
generateTest([20,null], [10,20], false);
generateTest([null,20], [20,30], false);
generateTest([20,30], [null,20], false);
});
describe('do overlap (one end overlaps)', function() {
generateTest([10,20], [19,30], true);
generateTest([19,30], [10,20], true);
generateTest([10,20], [null,30], true);
generateTest([10,20], [19,null], true);
generateTest([null,30], [10,20], true);
generateTest([19,null], [10,20], true);
});
describe('do overlap (one range included in other range)', function() {
generateTest([10,40], [20,30], true);
generateTest([20,30], [10,40], true);
generateTest([10,40], [null,null], true);
generateTest([null,null], [10,40], true);
});
describe('do overlap (both ranges equal)', function() {
generateTest([10,20], [10,20], true);
generateTest([null,20], [null,20], true);
generateTest([10,null], [10,null], true);
generateTest([null,null], [null,null], true);
});
});
Результат при запуске с кармой и жасмином & amp; PhantomJS:
PhantomJS 1.9.8 (Linux): выполнено 20 из 20 УСПЕХА (0.003 secs / 0.004 secs)
blockquote>
Start
иEnd
. Если у вас есть две переменные с именем Top и Bottom, или East and West, или HighValue и LoValue, можно предположить или подразумевать, что что-то или кто-то, где-то должно быть гарантией того, что одна из пар значений не будет храниться в противоположных переменных. -Только одна из двух пар, потому что, ну, она также будет работать, если обе пары значений будут переключаться. – Charles Bretana 5 August 2015 в 12:08start
иend
(с семантикой, которая «нулевой пуск» = «с начала времени» и «нулевой конец» = «до конца времени»), например что:(startA === null || endB === null || startA <= endB) && (endA === null || startB === null || endA >= startB)
– Kevin Robatel 26 February 2016 в 14:38