关于语言不可知:日期范围重叠与可空日期

Date Range Overlap with Nullable Dates

我在找一个问题的扩展答案:

确定两个日期范围是否重叠

其中任一日期范围内的任何日期都可以为空。我已经提出了以下解决方案,但我不确定是否可以进一步简化。

1
2
3
4
(StartA == NULL || StartA <= EndB) &&
(EndA == NULL || EndA >= StartB) &&
(StartB == NULL || StartB <= EndA) &&
(EndB == NULL || EndB >= StartA)

假设:

从starta到enda和startb到endb的日期时间范围

编辑:对不起,我很快就把上面的逻辑拼凑在一起了,当范围的开始日期和结束日期都为空时,这看起来是失败的。请参阅下面的David解决方案,以获得更好且解释清楚的方法。


这一案件可以通过对查尔斯·布雷塔纳对这个问题的完美答案的一点概括来处理。

0

在这种情况下,假设您希望一个空日期表示"没有开始/结束限制",那么条件将被修改。例如,对于CondA,为了使日期范围a完全在日期范围b之后,日期范围a必须有一个定义的开始时间,日期范围b必须有一个定义的结束时间,a的开始时间必须在b的结束时间之后:

1
CondA := (StartA != null) && (EndB != null) && (StartA > EndB)

CondB与A、B开关相同:

1
CondB := (StartB != null) && (EndA != null) && (StartB > EndA)

持续的,

Then Overlap exists if Neither A Nor B is true

2

Now deMorgan's law, I think it is, says that

Not (A Or B) <=> Not A And Not B

1
2
3
4
5
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的比较。在我熟悉的大多数语言中,这是一个错误条件。


不考虑空值,答案是

(StartA <= EndB) and (EndA >= StartB)(详细说明见此页)

考虑到开始和结束日期为空,使用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)以来就存在。在这种情况下,daterageb不能早于dateragea。因此,第一个条件(starta(bot)<=endb)将始终为真,无论endb是什么。因此,更改此表达式,以便在starta为空时,将endb与自身进行比较,而不是将null与endb进行比较无论endb是什么,表达式EndB <= EndB都是正确的。(我们可以创建变量来表示bot和eot,但这更简单)。

对其他三个输入变量执行相同的操作。


如果条件是真的,所有答案都是根据。我想在这里添加一些注释。

1-datetime变量类型是一个结构,除非使用"datetime?"之类的可空类型,否则不能将其设置为空。

2-要查找重叠范围,请执行以下步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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;
                }
            }

这可能是"简单"的,因为你可以得到它,虽然我还没有真正证明它。

进一步简化可能是不值得的,因为在最坏的情况下,该块最终会有8个操作(由于短路评估,平均为4个)。