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

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


当前回答

此处发布的解决方案不适用于所有重叠范围。。。

----------------------|-------A-------|----------------------
    |----B1----|
           |----B2----|
               |----B3----|
               |----------B4----------|
               |----------------B5----------------|
                      |----B6----|
----------------------|-------A-------|----------------------
                      |------B7-------|
                      |----------B8-----------|
                         |----B9----|
                         |----B10-----|
                         |--------B11--------|
                                      |----B12----|
                                         |----B13----|
----------------------|-------A-------|----------------------

我的工作解决方案是:

AND (
  ('start_date' BETWEEN STARTDATE AND ENDDATE) -- caters for inner and end date outer
  OR
  ('end_date' BETWEEN STARTDATE AND ENDDATE) -- caters for inner and start date outer
  OR
  (STARTDATE BETWEEN 'start_date' AND 'end_date') -- only one needed for outer range where dates are inside.
) 

其他回答

这是我的Java解决方案,它也适用于无限区间

private Boolean overlap (Timestamp startA, Timestamp endA,
                         Timestamp startB, Timestamp endB)
{
    return (endB == null || startA == null || !startA.after(endB))
        && (endA == null || startB == null || !endA.before(startB));
}

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

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

为了涵盖PHP/LaravelCarbon包中的所有重叠情况,您可以在Charles的答案中展开逻辑,如下所示。

if ( ($startTime1->between($startTime2, $endTime2, true) || $endTime1->between($startTime2, $endTime2, true)) || (($startTime1 <= $endTime2) && ($endTime2 <= $endTime1)) ){
//Complete Overlap, Partial Left Overlap, Partial Right Overlap. 
}

这将检查StartTime1是否在(StartTime2-EndTime2)范围之间,或者EndTime1是否位于(StartTime2-EndTime2的范围之间。

其余部分完全重叠,如其他答案所述。

关于时间关系(或任何其他区间关系)的推理,请考虑Allen的区间代数。它描述了两个区间之间可能存在的13种关系。你可以找到其他参考资料——“艾伦间隔”似乎是一个有效的搜索词。您还可以在Snodgrass的《用SQL开发面向时间的应用程序》(PDF,网址为)、《日期、达文和洛伦兹时间数据与关系模型》(2002年)或《时间与关系理论:关系模型与SQL中的时间数据库》(2014年;实际上是TD&RM的第二版)中找到有关这些操作的信息。


简短的答案是:给定两个日期间隔A和B,其中包含.start和.end以及约束.start<=.end,则两个间隔重叠,如果:

A.end >= B.start AND A.start <= B.end

您可以调整>=vs>和<=vs<的使用,以满足重叠程度的要求。


ErikE评论:

如果你数点有趣的事情,你只能得到13。。。当我疯狂地计算时,我可以得到“两个区间可以有15种可能的关系”。通过合理的计算,我只能得到6种关系,如果你不在乎A还是B先出现,我只能获得3种关系(不相交,部分相交,一种完全在另一种内)。15是这样的:[之前:之前,开始,内部,结束,之后],[开始:开始,内部、结束,之后】,[内部:内部,结束、之后],[结束:结束,之后,],[之后:之后]。

我认为你不能计算“之前:之前”和“之后:之后”这两个条目。如果你将某些关系与它们的逆关系等同起来,我可以看到7个条目(参见参考维基百科URL中的图表;它有7个条目,其中6个条目具有不同的逆关系,而equals没有不同的逆)。三个是否合理取决于你的要求。

----------------------|-------A-------|----------------------
    |----B1----|
           |----B2----|
               |----B3----|
               |----------B4----------|
               |----------------B5----------------|
                      |----B6----|
----------------------|-------A-------|----------------------
                      |------B7-------|
                      |----------B8-----------|
                         |----B9----|
                         |----B10-----|
                         |--------B11--------|
                                      |----B12----|
                                         |----B13----|
----------------------|-------A-------|----------------------

在Microsoft SQL SERVER中-SQL函数

CREATE FUNCTION IsOverlapDates 
(
    @startDate1 as datetime,
    @endDate1 as datetime,
    @startDate2 as datetime,
    @endDate2 as datetime
)
RETURNS int
AS
BEGIN
DECLARE @Overlap as int
SET @Overlap = (SELECT CASE WHEN  (
        (@startDate1 BETWEEN @startDate2 AND @endDate2) -- caters for inner and end date outer
        OR
        (@endDate1 BETWEEN @startDate2 AND @endDate2) -- caters for inner and start date outer
        OR
        (@startDate2 BETWEEN @startDate1 AND @endDate1) -- only one needed for outer range where dates are inside.
        ) THEN 1 ELSE 0 END
    )
    RETURN @Overlap

END
GO

--Execution of the above code
DECLARE @startDate1 as datetime
DECLARE @endDate1 as datetime
DECLARE @startDate2 as datetime
DECLARE @endDate2 as datetime
DECLARE @Overlap as int
SET @startDate1 = '2014-06-01 01:00:00' 
SET @endDate1 =   '2014-06-01 02:00:00'
SET @startDate2 = '2014-06-01 01:00:00' 
SET @endDate2 =   '2014-06-01 01:30:00'

SET @Overlap = [dbo].[IsOverlapDates]  (@startDate1, @endDate1, @startDate2, @endDate2)

SELECT Overlap = @Overlap