Date Range Overlap with Nullable Dates

前端 未结 4 1649
被撕碎了的回忆
被撕碎了的回忆 2021-02-10 03:23

I\'m looking for an extended answer to the question asked here:

Determine Whether Two Date Ranges Overlap

where any of the dates in either date range can be null

相关标签:
4条回答
  • 2021-02-10 03:51

    That is probably as 'simple' as you can get it, although I haven't actually proven it.

    It probably isn't worth it to simplify further, since that block ends up being about 8 operations in the worst case (4 on average thanks to short-circuit evaluation).

    0 讨论(0)
  • 2021-02-10 03:58

    This case can be handled by a slight generalization of Charles Bretana's excellent answer to that question.

    Let CondA Mean DateRange A Completely After DateRange B (True if StartA > EndB) Let CondB Mean DateRange A Completely Before DateRange B (True if EndA < StartB)

    In this case, assuming you want a null date to represent "no starting/ending bound," the conditions are modified. For CondA, for instance, in order for DateRange A to be completely after DateRange B, DateRange A must have a defined starting time, DateRange B must have a defined ending time, and the starting time of A must be after the ending time of B:

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

    CondB is the same with A and B switched:

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

    Continuing,

    Then Overlap exists if Neither A Nor B is true

    Overlap := !(CondA || CondB)
    

    and

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

    Not (A Or B) <=> Not A And Not 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)]
    

    I think this is actually a bit more robust than the solution you developed, because if EndB == NULL but StartA is not null, your first condition will wind up comparing StartA <= NULL. In most languages I'm familiar with, that's an error condition.

    0 讨论(0)
  • 2021-02-10 04:02

    Without considering nulls, answer is

    (StartA <= EndB) and (EndA >= StartB) (see this for detailed explanation)

    considering nulls for start and end dates,
    Using C Ternary operator syntax:
    (StartA != null? StartA: EndB <= EndB != null? EndB: StartA) && (EndA != null? EndA: StartB >= StartB != null? StartB: EndA)

    Or C# 4.x style null operators:

    (StartA??EndB <= EndB??StartA) && (EndA??StartB >= StartB??EndA)

    or in SQL:

    (Coalesce(StartA, EndB) <= Coalesce(EndB, StartA)) And (Coalesce(EndA, StartB ) <= Coalesce(StartB , EndA))

    Explanation:
    consider the non-null answer:
    (StartA <= EndB) and (EndA >= StartB)

    Now, consider that StartA is null, indicating that date range A has existed since beginning of time (BOT). In that case, DateRangeB can never be before DateRangeA. So first condition, (StartA(BOT) <= EndB) will ALWAYS be true, no matter what EndB is. So change this expression so that instead of comparing null with EndB, when StartA is null, compare EndB with itself No matter what EndB is, the expression EndB <= EndB will be true. (We could create variables to represent BOT and EOT, but this is easier).

    Do the same for other three input variables.

    0 讨论(0)
  • 2021-02-10 04:04

    All answers are based if the condition is true. I'would like to add some note here.

    1- The DateTime variable type is a struct and you can not set it to null unless that you are using nullable type like "DateTime?"

    2- To find the overlap range follow the following steps

    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;
                    }
                }
    
    0 讨论(0)
提交回复
热议问题