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

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


当前回答

关于时间关系(或任何其他区间关系)的推理,请考虑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-------|----------------------

其他回答

我认为,在以下情况下,两个范围重叠就足够了:

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)

我找到了另一个非常简单的方法。如果daterange1的开始和结束日期在daterange2的开始日期之前,或者daterange3的开始和终止日期在daterange2的结束日期之后,这意味着它们彼此不相交。

public boolean doesIntersect(DateRangeModel daterange1, DateRangeModel  daterange2) {
    return !(
            (daterange1.getStartDate().isBefore(daterange2.getStartDate())
                    && daterange1.getEndDate().isBefore(daterange2.getStartDate())) ||
                    (daterange1.getStartDate().isAfter(daterange2.getStartDate())
                            && daterange1.getEndDate().isAfter(daterange2.getEndDate())));
}

只要有简单的解决方案,仅仅使用额外的包来做简单的事情可能效率不高。但是,如果您已经在项目中使用了日期fns,那么有一个名为areIntervalsOverlapping的方法也会执行同样的操作。

语法:

areIntervalsOverlapping(intervalLeft, intervalRight, [options])

例子:

// For overlapping time intervals:
areIntervalsOverlapping(
  { start: new Date(2014, 0, 10), end: new Date(2014, 0, 20) },
  { start: new Date(2014, 0, 17), end: new Date(2014, 0, 21) }
)
//=> true

下面的查询给出了提供的日期范围(开始和结束日期)与table_name中的任何日期(开始和终止日期)重叠的ID

select id from table_name where (START_DT_TM >= 'END_DATE_TIME'  OR   
(END_DT_TM BETWEEN 'START_DATE_TIME' AND 'END_DATE_TIME'))

如果您提供一个日期范围作为输入,并希望找出它是否与数据库中的现有日期范围重叠,则以下条件可以成功满足您的需求

假设您从表单输入中提供了@StartDate和@EndDate。

条件是:

如果@StartDate在existingStartDate之前,而在existing EndDate之后,那么我们可以说@StartDate's在现有日期范围的中间,因此我们可以断定它将重叠

@StartDate >=existing.StartDate And @StartDate <= existing.EndDate) 

如果@StartDate在现有StartDate之后,而@EndDate在现有的StartDate之前,我们可以说它将重叠

 (@StartDate <= existing.StartDate And @EndDate >= existing.StartDate)

如果@StartDate晚于现有的StartDate,而@EndDate先于现有的EndDate,我们可以得出结论,所提供的日期范围吞噬了现有的日期范围,因此重叠

 (@StartDate <= existing.StartDate And @EndDate >= existing.EndDate))

如果任何条件成立,则提供的日期范围与数据库中的现有日期范围重叠。