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

Учитывая два диапазона дат, какой самый простой или эффективный способ определить, перекрываются ли два диапазона дат?

В качестве примера предположим, что мы имеем диапазоны, обозначенные переменными DateTime StartDate1 - EndDate1 и StartDate2 - EndDate2.

Ответы

Ответ 1

(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)

Тогда Overlap существует, если ни A Nor 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)


Note3. Благодаря @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)

Ответ 2

Я считаю, что достаточно сказать, что два диапазона перекрываются, если:

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

Ответ 3

В этой статье Библиотека периода времени для .NET описывается отношение двух периодов времени путем перечисления PeriodRelation:

// ------------------------------------------------------------------------
public enum PeriodRelation
{
    After,
    StartTouching,
    StartInside,
    InsideStartTouching,
    EnclosingStartTouching,
    Enclosing,
    EnclosingEndTouching,
    ExactMatch,
    Inside,
    InsideEndTouching,
    EndInside,
    EndTouching,
    Before,
} // enum PeriodRelation

enter image description here

Ответ 4

Для рассуждений о временных отношениях (или любых других интервальных отношениях, приходите к этому) рассмотрите Аллену Интервальной Аллена. Он описывает 13 возможных отношений, которые могут иметь два интервала по отношению друг к другу. Вы можете найти другие ссылки - "Аллен Интервал", кажется, оперативный поисковый термин. Вы также можете найти информацию об этих операциях в Snodgrass Разработка приложений, ориентированных на время, в SQL (PDF можно найти в Интернете по адресу URL), а также в Date, Darwen и Lorentzos Temporal Data and Relational Model (2002) или в Time and Relational Theory: Temporal Database в Реляционная модель и SQL (2014; фактически второе издание TD & RM).


Краткий (ish) ответ: с учетом двух интервалов дат A и B с компонентами .start и .end и ограничения .start <=.end, два интервала перекрываются, если:

A.end >= B.start AND A.start <= B.end

Вы можете настроить использование >= vs > и <= vs < чтобы удовлетворить ваши требования к степени перекрытия.


ErikE комментирует:

Вы можете получить только 13, если посчитаете вещи смешными... Я могу получить "15 возможных отношений, которые могут иметь два интервала", когда я схожу с ума от этого. Путем разумного подсчета я получаю только шесть, и если вы выбрасываете заботу о том, идет ли A или B первым, я получаю только три (нет пересечения, частично пересекается, одно полностью внутри другого). 15 выглядит следующим образом: [до: до, начало, внутри, конец, после], [начало: начало, внутри, конец, после], [внутри: внутри, конец, после], [конец: конец, после], [ после того, как: после].

Я думаю, что вы не можете сосчитать две записи "до: до" и "после: после". Я мог бы видеть 7 записей, если вы приравниваете некоторые отношения к их обратным ссылкам (см. Диаграмму в ссылочном URL-адресе Википедии; в нем 7 записей, 6 из которых имеют разные обратные значения, а равные не имеют четких обратных). И разумно ли три, зависит от ваших требований.

----------------------|-------A-------|----------------------
    |----B1----|
           |----B2----|
               |----B3----|
               |----------B4----------|
               |----------------B5----------------|
                      |----B6----|
----------------------|-------A-------|----------------------
                      |------B7-------|
                      |----------B8-----------|
                         |----B9----|
                         |----B10-----|
                         |--------B11--------|
                                      |----B12----|
                                         |----B13----|
----------------------|-------A-------|----------------------

Ответ 5

Если необходимо также рассчитать перекрытие, вы можете использовать следующую формулу:

overlap = max(0, min(EndDate1, EndDate2) - max(StartDate1, StartDate2))
if (overlap > 0) { 
    ...
}

Ответ 6

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

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

Предполагая включение с обоих концов, существует только четыре возможности, из которых одно не перекрывается:

|----------------------|        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 (для первого сегмента кода: во втором сегменте кода вы 'd используйте <, а не <=):

|----------------------|        range 1
|--->                           range 2 overlap
 |--->                          range 2 overlap
                       |--->    range 2 no overlap
                        |--->   range 2 no overlap

Вы сильно ограничиваете количество проверок, которые вы должны выполнить, потому что вы сначала удаляете половину проблемного пространства, гарантируя, что диапазон 1 никогда не запускается после диапазона 2.

Ответ 7

Вот еще одно решение с использованием 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);
    });
});

Результат при запуске с кармой & jasmine & PhantomJS:

PhantomJS 1.9.8 (Linux): Выполнено 20 из 20 УСПЕХА (0.003 secs/0.004 secs)

Ответ 8

Я бы сделал

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);
    }

Ответ 10

enter image description here

Вот код, который делает волшебство:

 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));

Куда..

  • A → 1старт
  • B → 1End
  • C → 2старт
  • D → 2End

Доказательство? Посмотрите эту суть кода тестовой консоли.

Ответ 11

Решение, размещенное здесь, не работает для всех перекрывающихся диапазонов...

----------------------|-------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.
) 

Ответ 12

Это мое решение для JavaScript с помощью функции moment.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;

Ответ 13

Здесь мое решение в 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));
}

Ответ 14

простейший

Самый простой способ - использовать хорошо спроектированную выделенную библиотеку для работы с датой.

someInterval.overlaps( anotherInterval )

java.time и ThreeTen-Extra

Лучшим в бизнесе является java.time framework, встроенный в Java 8 и более поздние версии. Добавьте к этому проект ThreeTen-Extra, который дополняет java.time дополнительными классами, в частности Interval, который нам нужен здесь.

Что касается тега language-agnostic в этом Вопросе, исходный код для обоих проектов доступен для использования на других языках (помните о своих лицензиях).

Interval

Класс org.threeten.extra.Interval удобен, но для этого требуются моменты времени дат (java.time.Instant objects), а не значения даты. Поэтому мы продолжаем использовать первый момент дня в формате 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 для определения промежутка времени, когда начало включено, а окончание является исключительным.

Ответ 15

Если вы используете диапазон дат, который еще не закончился (все еще продолжается), например. не задано 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 не перекрывается!

Ответ 16

Ответ слишком прост для меня, поэтому я создал более общий динамический оператор 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)

Ответ 17

Это расширение для отличного ответа от @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 right open

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 < 🞐 EndB) и (EndA > 🞐 StartB)

где 🞐 превращает строгое неравенство в нестрогий, когда делается сравнение между двумя включенными конечными точками.

Ответ 18

Самый простой способ сделать это, на мой взгляд, - сравнить, если либо EndDate1 до StartDate2, либо EndDate2 до StartDate1.

Это, конечно, если вы рассматриваете интервалы, где StartDate всегда находится перед EndDate.

Ответ 19

Вот общий метод, который может быть полезен локально.

    // 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
         */
    }

Ответ 20

В 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

Ответ 21

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");
            }

Ответ 22

Использование 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;
    }

Ответ 23

У меня была ситуация, когда у нас были даты, а не даты, и даты могут перекрываться только при запуске/завершении. Пример ниже:

введите описание изображения здесь

(Зеленый - текущий интервал, синие блоки - это допустимые интервалы, красные - перекрывающиеся интервалы).

Я адаптировал Яна Нельсона к следующему решению:

   (startB <= startA && endB > startA)
|| (startB >= startA && startB < endA)

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

Ответ 24

Математическое решение, данное @Bretana, является хорошим, но пренебрегает двумя конкретными деталями:

  • аспект закрытых или полуоткрытых интервалов
  • пустые интервалы

О закрытом или открытом состоянии интервальных границ, решение @Bretana допустимо для закрытых интервалов

(StartA <= EndB) и (EndA >= StartB)

можно переписать для полуоткрытых интервалов:

(StartA < EndB) и (EndA > StartB)

Эта коррекция необходима, потому что граница открытого интервала по определению не относится к диапазону значений интервала.


И о пустых интервалах, ну, здесь отношение, показанное выше, не выполняется. Пустые интервалы, которые не содержат допустимого значения по определению, должны обрабатываться как особый случай. В этом примере я продемонстрирую эту библиотеку 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 < endB), поэтому Time4J (и другие библиотеки тоже) должны обрабатывать его как специальный край, чтобы гарантировать, что перекрытие любого произвольного интервала с пустым интервалом не существует. Конечно, интервалы дат (которые закрыты по умолчанию в Time4J, но могут быть полуоткрытыми, также как и пустые интервалы даты) обрабатываются аналогичным образом.

Ответ 25

if (StartDate1 > StartDate2) swap(StartDate, EndDate);

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

Ответ 26

Разделить проблему на случаи, затем обрабатывать каждый случай.

Ситуация "два диапазона дат пересекаются" охватывает два случая: первый диапазон дат начинается во втором, или второй диапазон дат начинается с первого.

Ответ 27

Вы можете попробовать следующее:

//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);

Ответ 28

Это было мое решение, оно возвращает true, когда значения не перекрываются:

X ПУНКТ 1 Y END 1

СНВ 2 B КОНЕЦ 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

Ответ 29

Для 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-overlap-in-ruby-or-rails

Ответ 30

Ниже запроса отображаются идентификаторы, для которых заданный диапазон дат (даты начала и окончания совпадают с любой датой (датой начала и окончания) в моем имени таблицы

select id from table_name where (START_DT_TM >= 'END_DATE_TIME'  OR   
(END_DT_TM BETWEEN 'START_DATE_TIME' AND 'END_DATE_TIME'))