我正在寻找对此处提出的问题的扩展答案:
Determine Whether Two Date Ranges Overlap
其中任一日期范围中的任何日期都可以为null。我想出了以下解决方案,但我不确定它是否可以进一步简化。
(StartA == NULL || StartA <= EndB) &&
(EndA == NULL || EndA >= StartB) &&
(StartB == NULL || StartB <= EndA) &&
(EndB == NULL || EndB >= StartA)
假设:
StartA到EndA和StartB到EndB的DateTime范围
编辑:抱歉,我很快将上述逻辑放在一起,当范围的开始和结束日期都为NULL时,这似乎失败了。请参阅下面的David的解决方案以获得更好的&amp;解释得很好的方法。
答案 0 :(得分:12)
这个案例可以通过Charles Bretana's excellent answer对该问题的略微概括来处理。
让CondA平均DateRange完全在DateRange B之后(如果StartA&gt; EndB则为真) 设CondB平均DateRange A完全在DateRange B之前(如果EndA&lt; StartB则为真)
在这种情况下,假设您希望空日期表示“无开始/结束边界”,则会修改条件。例如,对于CondA
,为了使DateRange A完全在DateRange B之后,DateRange A必须具有已定义的开始时间,DateRange B必须具有已定义的结束时间,和 A的时间必须在B的结束时间之后:
CondA := (StartA != null) && (EndB != null) && (StartA > EndB)
CondB
与A和B切换相同:
CondB := (StartB != null) && (EndA != null) && (StartB > EndA)
继续,
如果A Nor B都不成立则存在重叠
Overlap := !(CondA || CondB)
和
现在deMorgan的法律,我认为是,
不(A或B)&lt; =&gt;不是A而不是B
Overlap == !CondA && !CondB
== ![(StartA != null) && (EndB != null) && (StartA > EndB)] &&
![(StartB != null) && (EndA != null) && (StartB > EndA)]
== [(StartA == null) || (EndB == null) || (StartA <= EndB)] &&
[(StartB == null) || (EndA == null) || (StartB <= EndA)]
我认为这实际上比您开发的解决方案更强大,因为如果EndB == NULL
但StartA
不为空,那么您的第一个条件将会比较StartA <= NULL
。在我熟悉的大多数语言中,这是一个错误条件。
答案 1 :(得分:0)
尽管我还没有真正证明这一点,但这可能是“简单”的。
进一步简化可能是不值得的,因为在最坏的情况下,该块最终会进行大约8次操作(由于短路评估,平均为4次)。
答案 2 :(得分:0)
如果条件为真,所有答案均以此为基础。我想在这里补充说明。
1- DateTime变量类型是一个结构,除非你使用像“DateTime?”这样的可空类型,否则你不能将它设置为null。
2-要查找重叠范围,请执行以下步骤
DateTime? StartOverLap = null,EndOverLap = null;
if (StartA != null && StartB != null)
{
StartOverLap = StartA > StartB ? StartA : StartB;
}
else if (StartA == null && StartB != null)
{
StartOverLap = StartB;
}
else if (StartA != null && StartB == null)
{
StartOverLap = StartA;
}
if (EndA != null && EndB != null)
{
EndOverLap = EndA < EndB ? EndA : EndB;
}
else if (EndA == null && EndB != null)
{
EndOverLap = EndB;
}
else if (EndA != null && EndB == null)
{
EndOverLap = EndA;
}
if (StartOverLap != null && EndOverLap == null)
{
if (EndOverLap < StartOverLap)
{
StartOverLap = null;
EndOverLap = null;
}
}
答案 3 :(得分:0)
不考虑空值,答案是
(StartA <= EndB) and (EndA >= StartB)
(详见this)
考虑开始日期和结束日期的空值,
使用C三元运算符语法:
(StartA != null? StartA: EndB <= EndB != null? EndB: StartA) &&
(EndA != null? EndA: StartB >= StartB != null? StartB: EndA)
或C#4.x样式空操作符:
(StartA??EndB <= EndB??StartA) && (EndA??StartB >= StartB??EndA)
或在SQL中:
(Coalesce(StartA, EndB) <= Coalesce(EndB, StartA))
And (Coalesce(EndA, StartB ) <= Coalesce(StartB , EndA))
说明:
考虑非空答案:
(StartA <= EndB) and (EndA >= StartB)
现在,考虑StartA为空,表示日期范围A自开始时间(BOT)起已存在。在这种情况下,DateRangeB永远不会出现在DateRangeA之前。因此,无论EndB是什么,第一个条件(StartA(BOT)&lt; = EndB)都将始终为真。因此,更改此表达式,以便在StartA为null时,将EndB与其自身进行比较,而不是将null与EndB进行比较
无论EndB是什么,表达式EndB <= EndB
都将为真。
(我们可以创建表示BOT和EOT的变量,但这更容易)。
对其他三个输入变量执行相同操作。