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

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


当前回答

这是我使用moment.js的javascript解决方案:

// Current row dates
var dateStart = moment("2014-08-01", "YYYY-MM-DD");
var dateEnd = moment("2014-08-30", "YYYY-MM-DD");

// Check with dates above
var rangeUsedStart = moment("2014-08-02", "YYYY-MM-DD");
var rangeUsedEnd = moment("2014-08-015", "YYYY-MM-DD");

// Range covers other ?
if((dateStart <= rangeUsedStart) && (rangeUsedEnd <= dateEnd)) {
    return false;
}
// Range intersects with other start ?
if((dateStart <= rangeUsedStart) && (rangeUsedStart <= dateEnd)) {
    return false;
}
// Range intersects with other end ?
if((dateStart <= rangeUsedEnd) && (rangeUsedEnd <= dateEnd)) {
    return false;
}

// All good
return true;

其他回答

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");
            }

将问题分为几个案例,然后处理每个案例。

“两个日期范围相交”的情况有两种情况:第一个日期范围从第二个开始,或者第二个日期范围在第一个开始。

使用momentjs的简短回答:

function isOverlapping(startDate1, endDate1, startDate2, endDate2){ 
    return moment(startDate1).isSameOrBefore(endDate2) && 
    moment(startDate2).isSameOrBefore(endDate1);
}

答案基于上述答案,但缩短了。

这是一段神奇的代码:

 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)