C# 如何检查日期时间段的交集

C# 如何检查日期时间段的交集,c#,datetime,C#,Datetime,我有四个DateTime对象。 A1、A2和B1、B2 我需要知道周期A1-A2与周期B1-B2不相交。但我不想像许多if块那样编写脏代码 if (A1 < B1 && A2 > B1) { return false; } 我不相信会有任何形式的“简单”代码来编写;您必须考虑4个不同的用例。如果需要经常进行这种检查,我会编写一个扩展方法。否则,您只需检查以下条件: |--- Date 1 ---| | --- Date 2 --- |

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

我需要知道周期A1-A2与周期B1-B2不相交。但我不想像许多if块那样编写脏代码

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

我不相信会有任何形式的“简单”代码来编写;您必须考虑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;
    }
}
公共类日期时间范围
{
公共日期时间开始{get;set;}
公共日期时间结束{get;set;}
公共布尔交叉(日期时间范围测试)
{
if(this.Start>this.End | | test.Start>test.End)
抛出新的InvalidDateRangeException();
if(this.Start==this.End | | test.Start==test.End)
返回false;//没有实际的日期范围
if(this.Start==test.Start | | this.End==test.End)
return true;//如果任何一个集合是同一时间的,则默认情况下必须有一些重叠。
if(this.Starttest.Start&&this.Endtest.End)
返回true;//条件3
}
其他的
{
if(test.End>this.Start&&test.Endthis.End)
返回true;//条件4
}
返回false;
}
}
这应该包括用例

没有办法绕过它:

*为简化而编辑:

假设B2>B1和A2>A1:

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

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


如果在您的程序中,A1-A2和B1-B2的范围在已知A1=的意义上是“适当的”。运算符的正确选择取决于您如何定义范围以包括或排除其端点,即它们是否表示闭合、开放或半开放间隔。

我想您可以这样做!((end2结束1)):

DateTime start1=新的DateTime(1);
DateTime end1=新的DateTime(2);
DateTime start2=新的DateTime(1);
DateTime end2=新的DateTime(2);
Console.WriteLine(!((end2end1));//返回true
[或]

DateTime start1=新的DateTime(1);
DateTime end1=新的DateTime(2);
DateTime start2=新的DateTime(3);
DateTime end2=新的DateTime(4);
Console.WriteLine(!((end2end1));//返回false

我的方法是创建一个名为
Period
的类,它包含
开始
结束
属性(日期时间)。此类可以有方法或扩展方法来计算交叉点。假设在Period类中有这样的方法:

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

您尝试的代码有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;
        }
    }
}
类范围,其中T:i可比较
{
公共T开始{get;私有集;}
公共T端{get;私有集;}
公共范围(T开始,T结束)
{
//始终确保开始<结束
如果(开始比较到(结束)>=0)
{
var-temp=结束;
结束=开始;
启动=温度;
}
开始=开始;
结束=结束;
}
}
静态类范围
{
//根据Eric的想法做负面检查
//有多少种方式可以使范围不重叠。
公共静态布尔值重叠(范围左、范围右)
其中T:i可比较
{
如果(右.开始.比较到(左.结束)>0)
返回false;
如果(左.开始.比较到(右.结束)>0)
返回false;
返回true;
}
公共静态布尔重叠(范围左、范围右)
其中T:i可比较
{
if(left.Start.CompareTo(right.Start)==0)
{
返回true;
}
如果(left.Start.CompareTo(right.Start)>0,则为else
{
返回left.Start.CompareTo(right.End)
public bool重叠(DateTime startDate1、DateTime endDate1、DateTime startDate2、DateTime endDate2)
{
如果(endDate1>=startDate2&&endDate2>=startDate1)
{
返回true;
}
如果(startDate1
DateTime[]start=newdatetime[]{newdatetime(2000,1,1),newdatetime(2004,1,1),
新日期时间(2004,1,1),新日期时间(2008,1,1)};
/*起始日期*/
DateTime[]end=newdatetime[]{newdatetime(2002,1,1),newdatetime(2006,1,1),
新日期时间(2006,1,1),新日期时间(2010,1,1)};/*结束日期*/
整数时差;
时间跨度时间跨度;
/*钮扣*/
{/*查找注释重叠的总天数*/
for(int i=0;i=end[i])
{
timespan=(结束[i]-开始[i])+(结束[i+1]-结束[i]);
}

如果(end[i]>=end[i+1]&&start[i]end[i+1]&&start[i]>start[i+1]&&start[i]那么检查您的时间段是否不重叠如何?如果不重叠条件为false,则表示它们确实重叠:

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

这个单元测试类通过Tejs使用
DateTimeRange
类(修改的构造函数)与上述解决方案一起进行。他的解决方案是正确的,这些测试证明了这一点(以防您想复制到生产中。:)


你是否已经确定
A1我不认为这样的代码是肮脏的,我认为你能/必须做的最好的事情就是简单地调用变量
if(A1>B2 || B1>A2)
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
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
public bool IntersectsWith(Period otherPeriod)
{
    return !(this.Start > otherPeriod.End || this.End < otherPeriod.Start);
}
if (!periodA.IntersectsWith(periodB))
{
    return false;
}
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;
        }
    }
}
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;
        }
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()); 
  }
        }}
    bool NotOverlapping = (start1 < start2 && end1 < start2) || (start1 > end2 && end1 > end2); 
    return !NotOverlapping // !NotOverlapping == Overlapping
[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));
    }
}