C# 如何检查日期时间段的交集
我有四个DateTime对象。 A1、A2和B1、B2 我需要知道周期A1-A2与周期B1-B2不相交。但我不想像许多if块那样编写脏代码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 --- |
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;
}
如果(startDate1DateTime[]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));
}
}