PHP - проверить, проходит ли дата другой [дубликат]

1016
задан David Faber 29 January 2015 в 03:07
поделиться

30 ответов

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

1874
ответ дан Charles Bretana 22 August 2018 в 16:29
поделиться
  • 1
    Это упрощенная логика, основанная на этих двух предположениях: 1) StartA & lt; EndA; 2) StartB & lt; EndB. Это кажется очевидным, но на самом деле данные могут поступать из неизвестного источника, такого как пользовательский ввод, или базы данных без дезинфекции. Имейте в виду, что вам нужно будет проверить входные данные, чтобы убедиться, что эти два предположения истинны, прежде чем вы сможете использовать эту упрощенную логику или все будет разваливаться. Урок, извлеченный из моего собственного опыта;) – Devy 27 July 2015 в 19:08
  • 2
    @Devy, Ты прав. За исключением того, что он также будет работать, если startA = endA. В самом деле, это именно то, что означают слова Start и End. Если у вас есть две переменные с именем Top и Bottom, или East and West, или HighValue и LoValue, можно предположить или подразумевать, что что-то или кто-то, где-то должно быть гарантией того, что одна из пар значений не будет храниться в противоположных переменных. -Только одна из двух пар, потому что, ну, она также будет работать, если обе пары значений будут переключаться. – Charles Bretana 5 August 2015 в 12:08
  • 3
    @rashid, вот сообщение , может дать вам несколько советов о том, как получить фактическое количество перекрытий. – Baodad 15 December 2015 в 18:39
  • 4
    Вы можете легко добавить nullable start и end (с семантикой, которая «нулевой пуск» = «с начала времени» и «нулевой конец» = «до конца времени»), например что: (startA === null || endB === null || startA <= endB) && (endA === null || startB === null || endA >= startB) – Kevin Robatel 26 February 2016 в 14:38
  • 5
    Лучший ответ на Stackexchange! Мне приятно видеть объяснение, почему эта умная формула работает! – Abeer Sul 12 March 2016 в 23:36

самый простой

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

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 .

2
ответ дан Basil Bourque 22 August 2018 в 16:29
поделиться

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

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

0
ответ дан Colonel Panic 22 August 2018 в 16:29
поделиться

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

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

1
ответ дан Darío Pm 22 August 2018 в 16:29
поделиться

Я бы сделал

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
ответ дан Echilon 22 August 2018 в 16:29
поделиться
  • 1
    Я бы предпочел (left & lt; value & amp; & amp; value & lt; right) || (справа & lt; значение & amp; & amp; значение & lt; left) для этого метода. – Patrick Huizinga 28 November 2008 в 16:22
  • 2
    Спасибо за это. Делает вещи легче в моей голове. – sshow 10 November 2009 в 16:05
  • 3
    Почему бы вам проверить четыре условия, когда вам нужно только проверить два? Потерпеть неудачу. – ErikE 9 March 2010 в 02:19
  • 4
    О, мои извинения, теперь я вижу, что вы разрешаете диапазоны в обратном порядке (StartDateX & gt; EndDateX). Странный. В любом случае, что, если StartDate1 меньше StartDate2, а EndDate1 больше, чем EndDate2? Код, который вы указали, не обнаружит это перекрывающееся условие. – ErikE 11 March 2010 в 06:17
  • 5
    – user158037 11 August 2015 в 13:06

Это было мое решение, оно возвращает 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
0
ответ дан Fez Vrasta 22 August 2018 в 16:29
поделиться

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

//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
ответ дан Guilherme Franco 22 August 2018 в 16:29
поделиться

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

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

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

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

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

1
ответ дан Gus 22 August 2018 в 16:29
поделиться

Это мое решение для 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;
4
ответ дан Ignacio Pascual 22 August 2018 в 16:29
поделиться

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

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
324
ответ дан jjnguy 22 August 2018 в 16:29
поделиться
  • 1
    Я считаю, что обозначение (StartDate1 <= EndDate2) and (EndDate1 >= StartDate2) легче понять, Range1 всегда остается слева в тестах. – A.L 2 December 2013 в 16:46
  • 2
    Это предполагает, что даты начала и окончания являются инклюзивными. Измените <= на <, если включение включено, а конец - исключительным. – Richard Schneider 9 April 2014 в 03:54
  • 3
    Это будет работать очень хорошо, даже если startDate2 до startDate1. Поэтому нет необходимости предполагать, что startDate1 раньше, чем startDate2. – Shehan Simen 6 February 2015 в 06:04
  • 4

Для рассуждений о временных соотношениях (или любых других интервальных соотношениях, приходим к этому), рассмотрим интервальную алгебру Аллена . Он описывает 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-------|----------------------
66
ответ дан Jonathan Leffler 22 August 2018 в 16:29
поделиться
  • 1
    Вы можете получить только 13, если посчитать смешные вещи ... Я могу получить «15 возможных отношений, которые могут иметь два интервала» когда я схожу с ума. Разумным подсчетом, я получаю только шесть, и если вы выбрасываете заботу о том, стоит ли сначала A или B, я получаю только три (не пересекаюсь, частично пересекаюсь, один полностью внутри другого). 15 выполняется следующим образом: [before: before, start, inside, end, after], [start: start, inside, end, after], [внутри: внутри, после, после], [конец: конец, после], [ после того, как: после]. – ErikE 9 March 2010 в 02:18
  • 2
    @Emtucifor: Я думаю, что вы не можете считать две записи «раньше: до» и «после: после». – Jonathan Leffler 9 March 2010 в 03:37
  • 3
    Повторите свое обновление: от B1 до A до: before и B13 - A после: after. У вашей красивой диаграммы отсутствует старт: начните между B5 B6, а конец: конец между B11 и B12. Если быть на конечной точке значимо, тогда вы должны считать это, поэтому окончательный результат равен 15, а не 13. Я не думаю, что конечная точка важна, поэтому я лично считаю ее [до : до, внутри, после], [внутри: внутри, после], [после: после], который приходит к 6. Я думаю, что вся конечная цель - просто путаница в том, являются ли ограничения инклюзивными или эксклюзивными. Исключительность конечных точек не меняет основных отношений! – ErikE 10 March 2010 в 21:38
  • 4
    То есть в моей схеме они эквивалентны: (B2, B3, B4), (B6, B7, B9, B10), (B8, B11, B12). Я понимаю, что B7 подразумевает информацию о том, что два диапазона точно совпадают. Но я не уверен, что эта информация дополнительная должна быть частью базовых отношений пересечения. Например, когда два интервала имеют одинаковую длину, даже если они не совпадают или даже перекрываются, следует ли это считать другим «отношением»? Я говорю «нет», и, видя, что этот дополнительный аспект - единственное, что делает B7 отличным от B6, тогда я думаю, что наличие конечных точек как отдельных дел делает вещи непоследовательными. – ErikE 10 March 2010 в 21:51
  • 5
    – Jonathan Leffler 10 March 2010 в 22:07

Вот мое решение в 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));
}
5
ответ дан Khaled.K 22 August 2018 в 16:29
поделиться
  • 1
  • 2
  • 3
    !startA.after(endB) означает, что startA & lt; = endB и !endA.before(startB) означает startB & lt; = endA. Это критерии для замкнутого интервала, а не открытого интервала. – Henrik 4 October 2017 в 12:03
  • 4
    @Henrik true, а другие условия, такие как endB == null и startA == null, проверяют открытый интервал. – Khaled.K 4 October 2017 в 14:32
  • 5
    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]

0
ответ дан mahatmanich 22 August 2018 в 16:29
поделиться
if (StartDate1 > StartDate2) swap(StartDate, EndDate);

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1);
0
ответ дан Marek Grzenkowicz 22 August 2018 в 16:29
поделиться
  • 1
    Достаточно второй линии. Какова цель первой строки? К чему относятся StartDate и EndDate? – 0xF 22 October 2013 в 12:20

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

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

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

1
ответ дан Meno Hochschild 22 August 2018 в 16:29
поделиться
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 22 August 2018 в 16:29
поделиться
  • 1
    Не возражаете, чтобы добавить некоторые объяснения? – Kling Klang 18 July 2014 в 18:31

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

----------------------|-------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_ 22 August 2018 в 16:29
поделиться

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

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

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

16
ответ дан paxdiablo 22 August 2018 в 16:29
поделиться
  • 1
    +1 для упоминания инклюзивной / исключительной проблемы. Я собирался ответить на вопрос, когда у меня было время, но теперь не нужно. Дело в том, что вы почти никогда не позволяете одновременно включать и начало и конец. В моей отрасли принято считать, что старт как эксклюзивный, а конечный - как включающий, но в любом случае все в порядке, пока вы остаетесь последовательными. Это первый полностью правильный ответ по этому вопросу до сих пор ... ИМО. – Brian Gideon 6 August 2010 в 04:50

В 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 22 August 2018 в 16:29
поделиться

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

 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

Доказательство? Проверьте этот тест gist .

4
ответ дан sandeep talabathula 22 August 2018 в 16:29
поделиться

Использование 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 22 August 2018 в 16:29
поделиться

Ниже запроса отображаются идентификаторы, для которых заданный диапазон дат (даты начала и окончания совпадают с любой датой (датой начала и окончания) в моей таблице_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'))
0
ответ дан Shravan Ramamurthy 22 August 2018 в 16:29
поделиться

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

    // 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 22 August 2018 в 16:29
поделиться

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

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

8
ответ дан Stefan Haberl 22 August 2018 в 16:29
поделиться

Ответ слишком прост для меня, поэтому я создал более общий динамический оператор 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 22 August 2018 в 16:29
поделиться
87
ответ дан user 22 August 2018 в 16:29
поделиться

Это расширение к отличному ответу 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>

2
ответ дан user2314737 22 August 2018 в 16:29
поделиться
  • 1
    Случаи два, три и четыре имеют одно и то же условие Overlap, является ли это преднамеренным? – Marie 22 November 2017 в 15:09
  • 2
    @Marie, я просто перечислил несколько случаев (не все) – user2314737 22 November 2017 в 18:34

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

overlap = max(0, min(EndDate1, EndDate2) - max(StartDate1, StartDate2))
if (overlap > 0) { 
    ...
}
25
ответ дан Vitalii Fedorenko 22 August 2018 в 16:29
поделиться
  • 1
    поэтому перекрытие - это количество времени, которое разделяет два события? Означает ли это, что все это происходит по-разному, события могут перекрываться? – NSjonas 9 September 2016 в 20: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 нет перекрытия!

2
ответ дан Will 22 August 2018 в 16:29
поделиться

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

12
ответ дан yankee 22 August 2018 в 16:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: