如何检查DateTime期间的交集

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

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

if (A1  B1) { return false; } 

….等

EDITED

我尝试使用这个: 比较范围

 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(A1, A2), new Range(B1, B2) )); 

它返回true但我预计会错误 。 因为此代码始终返回true

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

我不相信会有任何forms的“简单”代码写入; 你必须考虑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; } } 

这应该涵盖用例。

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

那你的非相交测试很简单

 if(A1>B2 || B1>A2) 

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

.NET的时间段库看起来很有趣。

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

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

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

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

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

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

试试这个:

 class Range where T : IComparable { 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(Range left, Range right) where T : IComparable { if (right.Start.CompareTo(left.End) > 0) return false; if (left.Start.CompareTo(right.End) > 0) return false; return true; } public static bool Overlap(Range left, Range right) where T : IComparable { 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; } } } 

没办法:

*编辑简化:

假设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 } 

此unit testing类使用DateTimeRange类(修改后的构造函数)伴随Tejs的上述解决方案。 他的解决方案是正确的,这些测试certificate了它(如果你想复制到生产中 。:))

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

我想你可以这样做!((end2 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 

[要么]

 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 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[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