如何检查DateTime周期的交集

时间:2011-09-06 19:30:27

标签: c# datetime

我有四个DateTime对象。 A1,A2和B1,B2。

我需要知道A1-A2期间与期间B1-B2不相交。但我不想写脏代码,就像很多块一样。

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

.... 等

EDITED

我尝试使用这个:Comparing ranges

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;
 }

11 个答案:

答案 0 :(得分:41)

如果在您的程序中,A1-A2和B1-B2的范围是“正确的”,因为已知A1 <= A2且B1 <= B2

然后您的非相交测试就是

if(A1>B2 || B1>A2)

注意我已经掩饰了这是否是&gt;或&gt; =。正确选择运算符取决于您如何定义范围以包含或排除其端点;即它们是代表封闭,开放还是半开放的间隔。

答案 1 :(得分:35)

我不相信会有任何形式的“简单”代码写入;你必须考虑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 :(得分:25)

Time Period Library for .NET看起来很有趣。

  

可以方便地查询IsSamePeriod,HasInside,OverlapsWith或IntersectsWith等方法,以查询此类期间关系的特殊常用变体。

答案 3 :(得分:15)

我的方法是创建一个名为Period的类,其中包含StartEnd属性(DateTime)。这个类可以有方法或扩展方法来计算交叉点之类的东西。假设您在Period类中有这样的方法:

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

然后你可以写这样的代码:

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

答案 4 :(得分:5)

您尝试过的代码有bug,我已修复它:

试试这个:

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's 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;
        }
    }
}

答案 5 :(得分:2)

无处可去:

*为简化而编辑:

假设B2&gt; B1和A2&gt; A1:

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

这将检测A1-A2的任何部分是否在B1-B2中。

如果你需要在B1-B2中检测A1-A2是否完全

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

答案 6 :(得分:2)

此单元测试类使用DateTimeRange类(修改后的构造函数)通过​​ Tejs 伴随上述解决方案。他的解决方案是正确的,这些测试证明了这一点(如果你想复制到生产。:)。

[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));
    }
}

答案 7 :(得分:1)

我认为你可以这样做!((end2&lt; start1)||(start2&gt; 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

答案 8 :(得分:1)

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;
        }

答案 9 :(得分:0)

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

答案 10 :(得分:0)

检查您的时间段是否重叠怎么样?然后,如果非重叠条件为假,则意味着它们重叠:

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