给定两个日期范围,确定两个日期是否重叠的最简单或最有效的方法是什么?

例如,假设我们有由DateTime变量StartDate1到EndDate1和StartDate2到EndDate2表示的范围。


当前回答

这是一段神奇的代码:

 var isOverlapping =  ((A == null || D == null || A <= D) 
            && (C == null || B == null || C <= B)
            && (A == null || B == null || A <= B)
            && (C == null || D == null || C <= D));

哪里

A->1启动B->1结束C->2启动D->2结束

证据查看此测试控制台代码要点。

其他回答

(起点A<=终点B)和(终点A>=起点B)

证明:让条件A表示日期范围A完全在日期范围B之后

_                        |---- DateRange A ------|
|---Date Range B -----|                          _

(如果StartA>EndB,则为True)

让条件B表示日期范围A完全在日期范围B之前

|---- DateRange A -----|                        _ 
_                          |---Date Range B ----|

(如果EndA<StartB,则为True)

如果A和B都不为真,则存在重叠-(如果一个范围既不完全在另一个范围之后,也不完全在另一个之前,则它们必须重叠。)

现在,德摩根的一项法律规定:

不是(A或B)<=>不是A也不是B

转换为:(StartA<=EndB)和(EndA>=StartB)


注意:这包括边缘完全重叠的情况。如果你想排除这一点,将>=运算符更改为>,并将<=更改为<


注2.多亏了@宝爸,看看这个博客,实际的重叠最少:{endA startA,endA-startB,endB startA,end B-startB}

(起点A<=终点B)和(终点A>=起点B)(开始A<=结束B)和(开始B<=结束A)


注3.多亏了@tomosius,一个简短的版本写道:DateRangesOverlap=最大值(start1,start2)<最小值(end1,end2)这实际上是一个较长实现的语法快捷方式,它包括额外的检查,以验证开始日期是否在结束日期之前。从上面得出:

如果开始日期和结束日期可能是无序的,即,如果startA>endA或startB>endB是可能的,那么您还必须检查它们是否有序,这意味着您必须添加两个额外的有效性规则:(StartA<=EndB)和(StartB<=EndA)以及或:(开始A<=结束B)和(开始A<=结束A)以及(开始B<=结束A”和(开始B<=结束B”)或(开始A<=最小值(结束A,结束B)和(开始B<=最小(结束A、结束B))或:(最大值(开始A,开始B)<=最小值(结束A,结束B)

但要实现Min()和Max(),必须编写代码(使用C三进制表示简洁):((开始A>开始B)?开始A:开始B)<=((结束A<结束B)?端A:端B)

我认为最简单的方法是比较EndDate1是否在StartDate2之前,EndDate2是否在StartDate 1之前。

当然,如果您正在考虑StartDate总是在EndDate之前的时间间隔。

适合我的紧凑公式

class ValidityRuleRange {
        private final Date from;
        private final Date to;
    ...
    private boolean isOverlap(ValidityRuleRange vrr) {
        int c1 = from.compareTo(vrr.getTo());
        int c2 = to.compareTo(vrr.getFrom());
        return c1 == 0 || c2 == 0 || c1 + c2 == 0;
    }
public static class NumberExtensionMethods
    {
        public static Boolean IsBetween(this Int64 value, Int64 Min, Int64 Max)
        {
            if (value >= Min && value <= Max) return true;
            else return false;
        }

        public static Boolean IsBetween(this DateTime value, DateTime Min, DateTime Max)
        {
            Int64 numricValue = value.Ticks;
            Int64 numericStartDate = Min.Ticks;
            Int64 numericEndDate = Max.Ticks;

            if (numricValue.IsBetween(numericStartDate, numericEndDate) )
            {
                return true;
            }

            return false;
        }
    }

public static Boolean IsOverlap(DateTime startDate1, DateTime endDate1, DateTime startDate2, DateTime endDate2)
        {
            Int64 numericStartDate1 = startDate1.Ticks;
            Int64 numericEndDate1 = endDate1.Ticks;
            Int64 numericStartDate2 = startDate2.Ticks;
            Int64 numericEndDate2 = endDate2.Ticks;

            if (numericStartDate2.IsBetween(numericStartDate1, numericEndDate1) ||
                numericEndDate2.IsBetween(numericStartDate1, numericEndDate1) ||
                numericStartDate1.IsBetween(numericStartDate2, numericEndDate2) ||
                numericEndDate1.IsBetween(numericStartDate2, numericEndDate2))
            {
                return true;
            }

            return false;
        } 


if (IsOverlap(startdate1, enddate1, startdate2, enddate2))
            {
                Console.WriteLine("IsOverlap");
            }

本文《.NET时间段库》通过枚举PeriodRelation描述了两个时间段之间的关系:

// ------------------------------------------------------------------------
public enum PeriodRelation
{
    After,
    StartTouching,
    StartInside,
    InsideStartTouching,
    EnclosingStartTouching,
    Enclosing,
    EnclosingEndTouching,
    ExactMatch,
    Inside,
    InsideEndTouching,
    EndInside,
    EndTouching,
    Before,
} // enum PeriodRelation