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

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


当前回答

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

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

其他回答

简单的解决方案:

compare the two dates: 
    A = the one with smaller start date, B = the one with bigger start date
if(A.end < B.start)
    return false
return true

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

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

由于对于不同的语言和环境有多种答案,这里有一个标准ANSISQL的答案。

在标准SQL中,它非常简单

(StartDate1, EndDate1) overlaps (StartDate2, EndDate2)

假设所有四列都是DATE或TIMESTAMP列。如果两个范围至少有一天相同(假设DATE值),则返回true

(但并非所有DBMS产品都支持此功能)


在PostgreSQL中,使用日期范围也很容易测试是否包含

daterange(StartDate1, EndDate1) @> daterange(StartDate2, EndDate2)

如果第二个范围完全包含在第一个范围中(与“重叠”不同),则上述值返回真

我会的

StartDate1.IsBetween(StartDate2, EndDate2) || EndDate1.IsBetween(StartDate2, EndDate2)

IsBetween是这样的

    public static bool IsBetween(this DateTime value, DateTime left, DateTime right) {
        return (value > left && value < right) || (value < left && value > right);
    }

最简单的

最简单的方法是使用精心设计的专用库进行日期时间工作。

someInterval.overlaps( anotherInterval )

java.time&ThreeTen额外

业务中最好的是内置在Java8和更高版本中的java.time框架。添加ThreeTen Extra项目,该项目用额外的类来补充java.time,特别是我们这里需要的Interval类。

至于这个问题上的语言不可知标签,两个项目的源代码都可以在其他语言中使用(注意它们的许可证)。

间隔

org.threeten.extra.Interval类很方便,但需要日期时间瞬间(java.time.Instant对象),而不是仅日期值。因此,我们继续使用UTC中的一天的第一刻来表示日期。

Instant start = Instant.parse( "2016-01-01T00:00:00Z" );
Instant stop = Instant.parse( "2016-02-01T00:00:00Z" );

创建一个间隔来表示该时间跨度。

Interval interval_A = Interval.of( start , stop );

我们也可以用开始时刻加上持续时间来定义间隔。

Instant start_B = Instant.parse( "2016-01-03T00:00:00Z" );
Interval interval_B = Interval.of( start_B , Duration.of( 3 , ChronoUnit.DAYS ) );

比较和测试重叠很容易。

Boolean overlaps = interval_A.overlaps( interval_B );

您可以将“间隔”与另一个“间隔”或“即时”进行比较:

邻接,邻接包含外壳等于在之后是之前重叠,重叠

所有这些都使用半开放的方法来定义一段时间,其中开始是包容性的,结束是排他性的。