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

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

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

955
задан Ian Nelson 28 нояб. '08 в 17:48
источник поделиться

32 ответов

  • 1
  • 2

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

1828
ответ дан Charles Bretana 28 нояб. '08 в 18:00
источник поделиться

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

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
314
ответ дан Ian Nelson 28 нояб. '08 в 17:49
источник поделиться

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

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

enter image description here

87
ответ дан user687474 09 апр. '11 в 1:42
источник поделиться

Для рассуждений о временных отношениях (или любых других отношениях интервалов), рассмотрите Алленную алгебру Аллена. Он описывает 13 возможных отношений, которые могут иметь два интервала относительно друг друга. Вы можете найти другие ссылки - "Аллен Интервал", похоже, является оперативным поисковым термином. Вы также можете найти информацию об этих операциях в Snodgrass Разработка временных ориентированных приложений в SQL (PDF доступен онлайн по адресу URL), а также в Дате, Дарвине и Lorentzos Временные данные и реляционная модель (2002) или Время и теория отношений: Временные базы данных в реляционной модели и 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 выполняется следующим образом: [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-------|----------------------
65
ответ дан Jonathan Leffler 30 нояб. '08 в 9:54
источник поделиться

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

overlap = max(0, min(EndDate1, EndDate2) - max(StartDate1, StartDate2))
if (overlap > 0) { 
    ...
}
24
ответ дан Vitalii Fedorenko 06 сент. '12 в 5:07
источник поделиться

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

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

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

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

16
ответ дан paxdiablo 06 авг. '10 в 5:39
источник поделиться

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

11
ответ дан yankee 13 марта '15 в 16:19
источник поделиться

Я знаю, что это было отмечено как язык-агностик, но для всех вас, внедряющихся в Java: не изобретайте велосипед и не используйте Joda Time.

http://joda-time.sourceforge.net/api-release/org/joda/time/base/AbstractInterval.html#overlaps(org.joda.time.ReadableInterval)

8
ответ дан Stefan Haberl 13 окт. '12 в 18:10
источник поделиться

Я бы сделал

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);
    }
7
ответ дан Bob 28 нояб. '08 в 17:51
источник поделиться

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

----------------------|-------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.
) 
5
ответ дан on_ 05 нояб. '13 в 11:24
источник поделиться

Здесь мое решение в 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));
}
4
ответ дан Khaled.K 21 февр. '17 в 10:53
источник поделиться

Это мое решение для 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;
4
ответ дан Ignacio Pascual 12 сент. '13 в 23:28
источник поделиться

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

Вот код, который делает магию:

 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 → 1Start
  • B → 1End
  • C → 2Start
  • D → 2End

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

3
ответ дан sandeep talabathula 28 окт. '17 в 19:41
источник поделиться

простейший

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

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 для определения промежутка времени, когда начало включено, а окончание является исключительным.

2
ответ дан Basil Bourque 05 нояб. '16 в 2:30
источник поделиться

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

2
ответ дан jack 27 марта '14 в 19:47
источник поделиться

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

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

2
ответ дан user2314737 14 июня '17 в 21:57
источник поделиться
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");
            }
1
ответ дан mmarjeh 18 июля '14 в 20:12
источник поделиться

Использование 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;
    }
1
ответ дан Shehan Simen 06 февр. '15 в 8:21
источник поделиться

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

    // 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
         */
    }
1
ответ дан staceyw 13 апр. '09 в 8:14
источник поделиться

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

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

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

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

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

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

1
ответ дан Gus 18 янв. '17 в 17:06
источник поделиться

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

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

1
ответ дан AlexDrenea 28 нояб. '08 в 17:52
источник поделиться

Математическое решение, данное @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, но могут быть полуоткрытыми, также как и пустые интервалы даты) обрабатываются аналогичным образом.

1
ответ дан Meno Hochschild 10 апр. '17 в 8:56
источник поделиться

В 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
1
ответ дан Prasenjit Banerjee 05 июля '14 в 16:44
источник поделиться

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

Предположим, что вы предоставили @StartDate и @EndDate из ввода формы.

:

Если @StartDate опережает existingStartDate и позади existingEndDat e, мы можем сказать, что @StartDate находится в середине существующего диапазона дат, поэтому мы можем заключить, что он будет перекрываться

@StartDate >=existing.StartDate And @StartDate <= existing.EndDate) 

Если @StartDate находится за existingStartDate, но @EndDate опережает existingStartDate, мы можем сказать, что он будет перекрываться

 (@StartDate <= existing.StartDate And @EndDate >= existing.StartDate)

Если @StartDate находится за existingStartDate И @EndDate опережает existingEndDate, мы можем заключить, что предоставленный диапазон дат пожирает существующий диапазон дат, таким образом перекрывает

 (@StartDate <= existing.StartDate And @EndDate >= existing.EndDate))

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

0
ответ дан AL-zami 05 окт. '17 в 10:50
источник поделиться

Ответ слишком прост для меня, поэтому я создал более общий динамический оператор 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)
0
ответ дан Tom McDonough 09 дек. '16 в 19:16
источник поделиться

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

//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);
0
ответ дан Ilya 25 марта '14 в 16:42
источник поделиться

Простое решение:

compare the two dates: 
    A = the one with smaller start date, B = the one with bigger start date
if(A.end < B.start)
    return false
return true
0
ответ дан sorry_I_wont 20 янв. '17 в 9:17
источник поделиться

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

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

0
ответ дан Colonel Panic 13 окт. '12 в 2:17
источник поделиться

Для 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

0
ответ дан mahatmanich 25 окт. '15 в 2:40
источник поделиться
if (StartDate1 > StartDate2) swap(StartDate, EndDate);

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1);
0
ответ дан Syam 23 янв. '12 в 10:02
источник поделиться
  • 1
  • 2

Другие вопросы по меткам