我有四个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;
}
答案 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
的类,其中包含Start
和End
属性(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