Определите, перекрываются ли два диапазона дат - PullRequest
1104 голосов
/ 28 ноября 2008

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

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

Ответы [ 34 ]

1 голос
/ 18 июля 2014
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 голос
/ 18 января 2017

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

enter image description here

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

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

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

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

1 голос
/ 10 апреля 2017

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

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

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

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

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

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

0 голосов
/ 18 июля 2018

Вот еще один сокращенный ответ, используя momentjs :

function isOverlapping(startDate1, endDate1, startDate2, endDate2){ 
return moment(startDate1).isSameOrBefore(endDate2) && 
moment(startDate2).isSameOrBefore(endDate1);
}

ответ основан на приведенных выше ответах, но его сокращают.

0 голосов
/ 23 января 2012
if (StartDate1 > StartDate2) swap(StartDate, EndDate);

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1);
0 голосов
/ 05 октября 2017

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

Предположим, вы предоставляете @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 голосов
/ 13 октября 2012

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

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

0 голосов
/ 25 марта 2014

Вы можете попробовать это:

//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 голосов
/ 20 января 2017

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

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 голосов
/ 08 января 2019

Легко запомнить решение будет
min(ends)>max(starts)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...