Подтвердить что ты не робот

Как проверить пересечение периодов DateTime

У меня есть четыре объекта DateTime. A1, A2 и B1, B2.

Мне нужно знать, что период A1-A2 не пересекается с периодом B1-B2. Но я не хочу писать грязный код, как многие, если блоки.

if (A1 < B1 && A2 > B1)
{
    return false;
}

.... и др.

отредактированы

Я попытался использовать этот: Сравнение диапазонов

DateTime A1 = DateTime.MinValue.AddMinutes(61);
DateTime A2 = DateTime.MinValue.AddHours(1.2);
DateTime B1 = DateTime.MinValue.AddMinutes(5);
DateTime B2 = DateTime.MinValue.AddHours(1);

Console.WriteLine(Range.Overlap(
    new Range<DateTime>(A1, A2),
    new Range<DateTime>(B1, B2)
));

Он вернул true, но я ожидал false. Поскольку этот код всегда возвращает true

 if (left.Start.CompareTo(left.Start) == 0)
 {
     return true;
 }
4b9b3361

Ответ 1

Я не верю, что будет какой-нибудь способ "простого" кода писать; вы должны учитывать 4 различных варианта использования. Если вам нужно много чего сделать, я бы написал метод расширения. В противном случае вам просто нужно проверить эти условия:

 |--- Date 1 ---|
      | --- Date 2 --- |


      | --- Date 1 --- |
 | --- Date 2 ---- |


 | -------- Date 1 -------- |
      | --- Date 2 --- |

      | --- Date 1 --- |
 | -------- Date 2 -------- |

РЕДАКТИРОВАТЬ: предоставить фактический код:

public class DateTimeRange
{
     public DateTime Start { get; set; }
     public DateTime End { get; set; }

     public bool Intersects(DateTimeRange test)
     {
         if(this.Start > this.End || test.Start > test.End)
            throw new InvalidDateRangeException();

         if(this.Start == this.End || test.Start == test.End)
              return false; // No actual date range

         if(this.Start == test.Start || this.End == test.End)
              return true; // If any set is the same time, then by default there must be some overlap. 

         if(this.Start < test.Start)
         {
              if(this.End > test.Start && this.End < test.End)
                  return true; // Condition 1

              if(this.End > test.End)
                  return true; // Condition 3
         }
         else
         {
              if(test.End > this.Start && test.End < this.End)
                  return true; // Condition 2

              if(test.End > this.End)
                  return true; // Condition 4
         }

         return false;
    }
}

Это должно охватывать варианты использования.

Ответ 2

Если в вашей программе диапазоны A1-A2 и B1-B2 являются "правильными" в том смысле, что известно, что A1 <= A2 и B1 <= B2

то ваш тест без пересечения просто

if(A1>B2 || B1>A2)

Примечание. Я прочитал, что это > или > =. Правильный выбор оператора зависит от того, как вы определили диапазоны для включения или исключения своих конечных точек; т.е. представляют ли они замкнутые, открытые или полуоткрытые интервалы.

Ответ 3

Библиотека Time Period для .NET выглядит интересной.

Методы, такие как IsSamePeriod, HasInside, OverlapsWith или IntersectsWith доступны для удобства запросов для специальных, часто используемых вариантов таких отношений периода.

Ответ 4

Мой подход заключается в создании класса с именем Period, который содержит свойства Start и End (DateTime). Этот класс может иметь методы или методы расширения для вычисления таких вещей, как пересечения. Скажем, у вас есть такой метод в вашем классе Period:

public bool IntersectsWith(Period otherPeriod)
{
    return !(this.Start > otherPeriod.End || this.End < otherPeriod.Start);
}

Затем вы можете написать код следующим образом:

if (!periodA.IntersectsWith(periodB))
{
    return false;
}

Ответ 5

В коде, который вы пробовали, есть ошибка, я исправил его:

Попробуйте следующее:

class Range<T> where T : IComparable<T>
{
    public T Start { get; private set;}
    public T End { get; private set;}

    public Range(T start, T end)
    {
        //Always ensure that Start < End
        if(start.CompareTo(end) >= 0)
        {
            var temp = end;
            end = start;
            start = temp;
        }

        Start = start;
        End = end;
    }
}

static class Range
{
    //Based on Eric idea of doing negative check to figure out
    //how many ways there are for ranges to NOT overlap.
    public static bool EricOverlap<T>(Range<T> left, Range<T> right)
        where T : IComparable<T>
    {
        if (right.Start.CompareTo(left.End) > 0)
            return false;

        if (left.Start.CompareTo(right.End) > 0)
            return false;

        return true;
    }
    public static bool Overlap<T>(Range<T> left, Range<T> right)
        where T : IComparable<T>
    {
        if (left.Start.CompareTo(right.Start) == 0)
        {
            return true;
        }

        else if (left.Start.CompareTo(right.Start) > 0)
        {
            return left.Start.CompareTo(right.End) <= 0;
        }
        else
        {
            return right.Start.CompareTo(left.End) <= 0;
        }
    }
}

Ответ 6

Ничего не стоит вокруг:

* Отредактировано для упрощения:

Предполагая, что B2 > B1 и A2 > A1:

if (A2 >= B1 && A1 <= B2) {
    // some part of a1-a2 is in b1-b2
}

Это обнаружит, что какая-либо часть A1-A2 находится в B1-B2.

Если вам нужно определить, полностью ли A1-A2 находится в B1-B2:

if (B1 <= A1 && B2 >= A2) {
    // all of a1-a2 is in b1-b2
}

Ответ 7

Этот класс unit test сопровождает решение выше Tejs, используя класс DateTimeRange (модифицированный конструктор). Его решение правильное, и эти тесты подтверждают это (если вы хотите скопировать в производство:):)

[TestClass]
public class DateTimeRangeTests
{
    [TestMethod]
    public void overlap_dates_is_interscected_second_newer_test()
    {
        //|--- Date 1 ---|
        //    | --- Date 2 --- |
        DateTime baseTime = DateTime.Now;
        var r1 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-2));
        var r2 = new DateTimeRange(baseTime.AddDays(-3), baseTime.AddDays(-1));

        Assert.IsTrue(r1.Intersects(r2));
    }

    [TestMethod]
    public void overlap_dates_is_interscected_second_older_test()
    {
        //        |--- Date 1 ---|
        //    | --- Date 2 --- |
        DateTime baseTime = DateTime.Now;
        var r1 = new DateTimeRange(baseTime.AddDays(-3), baseTime.AddDays(-1));
        var r2 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-2));

        Assert.IsTrue(r1.Intersects(r2));
    }

    [TestMethod]
    public void overlap_dates_is_interscected_second_subset_of_first_test()
    {
        //| -------- Date 1 -------- |
        //   | --- Date 2 --- |
        DateTime baseTime = DateTime.Now;
        var r1 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-1));
        var r2 = new DateTimeRange(baseTime.AddDays(-3), baseTime.AddDays(-2));

        Assert.IsTrue(r1.Intersects(r2));
    }

    [TestMethod]
    public void overlap_dates_is_interscected_second_superset_of_first_test()
    {
        //| -------- Date 1 -------- |
        //   | --- Date 2 --- |
        DateTime baseTime = DateTime.Now;
        var r1 = new DateTimeRange(baseTime.AddDays(-3), baseTime.AddDays(-2));
        var r2 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-1));

        Assert.IsTrue(r1.Intersects(r2));
    }

    [TestMethod]
    public void non_intersects_dates_when_second_before_first_test()
    {
        //                        | --- Date 1 -------- |
        //   | --- Date 2 --- |
        DateTime baseTime = DateTime.Now;
        var r1 = new DateTimeRange(baseTime.AddDays(-1), baseTime.AddDays(0));
        var r2 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-2));

        Assert.IsFalse(r1.Intersects(r2));
    }

    [TestMethod]
    public void non_intersects_dates_when_second_after_first_test()
    {
        //   | --- Date 1 ------ |
        //                          | --- Date 2 --- |
        DateTime baseTime = DateTime.Now;
        var r1 = new DateTimeRange(baseTime.AddDays(-4), baseTime.AddDays(-2));
        var r2 = new DateTimeRange(baseTime.AddDays(-1), baseTime.AddDays(-0));

        Assert.IsFalse(r1.Intersects(r2));
    }
}

Ответ 8

Я думаю, вы можете сделать это так! ((end2 < start1) || (start2 > end1)):

DateTime start1 = new DateTime(1);
DateTime end1 = new DateTime(2);

DateTime start2 = new DateTime(1);
DateTime end2 = new DateTime(2);

Console.WriteLine(!( (end2 < start1) || (start2 > end1) )); //returns true

[OR]

DateTime start1 = new DateTime(1);
DateTime end1 = new DateTime(2);

DateTime start2 = new DateTime(3);
DateTime end2 = new DateTime(4);


Console.WriteLine(!( (end2 < start1) || (start2 > end1) )); // returns false

Ответ 9

public bool Overlap(DateTime startDate1, DateTime endDate1, DateTime startDate2, DateTime endDate2)
        {
            if (endDate1 >= startDate2 && endDate2 >= startDate1)
            {
                return true;
            }

            if (startDate1 <= endDate2 && startDate2 <= startDate1)
            {
                return true;
            }

            return false;
        }

Ответ 10

DateTime[] start = new DateTime[] { new DateTime(2000, 1, 1), new DateTime(2004, 1, 1),   
                                  new DateTime(2004, 1, 1), new DateTime(2008, 1, 1) };  
                 /*date that start from*/

DateTime[] end   = new DateTime[] { new DateTime(2002, 1, 1), new DateTime(2006, 1, 1),  
new DateTime(2006, 1, 1), new DateTime(2010, 1, 1) }; /*date that end */

int timeDifference ; 

TimeSpan timespan;

 /*buttonclick  */
    {     /*find total days which note overlap*/
    for (int i=0; i<end.Length-2; i++)
    {        
        if (end[i] < end[i + 1] && start[i] < start[i + 1] && start[i + 1] >= end[i])
            {
                timespan = (end[i] - start[i]) + (end[i + 1] - end[i]);        
    }

        if (end[i] >= end[i + 1] && start[i] <= start[i + 1])          
            {
                timespan = (end[i] - start[i]);            
        }
        if (end[i] > end[i + 1] && start[i] > start[i + 1] && start[i] <= end[i + 1])         
            {
                timespan = (end[i] - start[i]) + (end[i + 1] - end[i]);
            }
        if  (end[i] <= end[i + 1] && start[i] >= start[i + 1])    
            {        
                    timespan = (end[i + 1] - start[i + 1]);
            }

            timeDifference = timespan.Days + timeDifference;                          

        } 
              MessageBox.Show(timeDifference.ToString()); 
  }
        }}

Ответ 11

Как проверить, не перекрываются ли ваши периоды времени? Тогда, если условие не перекрытия является ложным, это означает, что они перекрывают:

    bool NotOverlapping = (start1 < start2 && end1 < start2) || (start1 > end2 && end1 > end2); 
    return !NotOverlapping // !NotOverlapping == Overlapping