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

Я создал плагин, который может генерировать эффект предварительного просмотра в IE 7+ благодаря интернету, но имеет мало ограничений. Я помещал его в github page , чтобы его было легче получить

$(function () {
		$("input[name=file1]").previewimage({
			div: ".preview",
			imgwidth: 180,
			imgheight: 120
		});
		$("input[name=file2]").previewimage({
			div: ".preview2",
			imgwidth: 90,
			imgheight: 90
		});
	});
.preview > div {
  display: inline-block;
  text-align:center;
}

.preview2 > div {
  display: inline-block; 
  text-align:center;
}


	Preview
	
Preview2

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

7 ответов

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

Доказательство:
ConditionA, которому Позволяют, Средний, что DateRange Полностью После DateRange B
_ |---- DateRange A ------| |---Date Range B -----| _
(Верный, если StartA > EndB)

ConditionB, которому Позволяют, Средний, что DateRange A Полностью Перед DateRange B
|---- DateRange A -----| _ _ |---Date Range B ----|
(Верный, если EndA < StartB)

Тогда, Перекрытие существует, если Ни A, Ни B не верны -
(Если один диапазон ни полностью после другого,
, ни полностью перед другим, то они должны наложиться.)

Теперь один из [1 127] законы De Morgan говорит что:

Not (A Or B) < => Not A And Not B

, Который переводит в: (StartA <= EndB) and (EndA >= StartB)

<час>

ПРИМЕЧАНИЕ: Это включает условия, где края накладываются точно. Если Вы хотите исключить, это,
изменяется эти >= операторы к >, и <= к [1 110]

<час>

NOTE2. Благодаря @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)
Это - на самом деле синтаксический ярлык для того, что является более длительной реализацией, которая включает дополнительные проверки, чтобы проверить, что даты начала идут или перед endDates. Получение этого сверху:

, Если запускаются и даты окончания не могут работать, т.е. если возможно, что startA > endA или startB > endB, тогда также необходимо проверить, что они в порядке, так, чтобы средства Вы добавили два дополнительных правила законности:
(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB) или:
(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB) или,
(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB)) или:
(Max(StartA, StartB) <= Min(EndA, EndB)

, Но реализовать Min() и Max(), необходимо кодировать, (использующий C троичный для краткости):
(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)

2100
ответ дан Charles Bretana 29 January 2015 в 02:07
поделиться

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

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
364
ответ дан jjnguy 29 January 2015 в 02:07
поделиться

Для обоснования о временных отношениях (или любых других отношениях интервала, приезжайте в тот), рассмотрите Интервальная алгебра Allen . Это описывает 13 возможных отношений, которые два интервала могут иметь друг относительно друга. Можно найти, что другие ссылки — "Интервал Allen", кажется, действующий критерий поиска. Можно также найти информацию об этих операциях в Snodgrass Разрабатывающие Ориентированные на время Приложения в SQL (PDF доступный онлайн в URL), и на Дате, Дарвене и Lorentzos Временные Данные и Реляционная модель (2002) или Время и Реляционная Теория: Временные Базы данных в Реляционной модели и SQL (2014; эффективно второй выпуск TD& RM).

<час>

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

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

можно настроить использование >= по сравнению с > и <= по сравнению с [1 110] для соответствия требованиям для степени перекрытия.

<час>

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

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

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

----------------------|-------A-------|----------------------
    |----B1----|
           |----B2----|
               |----B3----|
               |----------B4----------|
               |----------------B5----------------|
                      |----B6----|
----------------------|-------A-------|----------------------
                      |------B7-------|
                      |----------B8-----------|
                         |----B9----|
                         |----B10-----|
                         |--------B11--------|
                                      |----B12----|
                                         |----B13----|
----------------------|-------A-------|----------------------
73
ответ дан Jonathan Leffler 29 January 2015 в 02:07
поделиться

Я сделал бы

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);
    }
8
ответ дан Echilon 29 January 2015 в 02:07
поделиться

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

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

1
ответ дан Darío Pm 29 January 2015 в 02:07
поделиться

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

    // 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
ответ дан 19 December 2019 в 20:14
поделиться

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

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

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

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

18
ответ дан 19 December 2019 в 20:14
поделиться
Другие вопросы по тегам:

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