确定两个日期范围是否重叠

时间:2008-11-28 14:48:36

标签: datetime math language-agnostic

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

例如,假设我们的范围由DateTime变量StartDate1EndDate1 StartDate2EndDate2表示。

37 个答案:

答案 0 :(得分:2069)

(StartA< = EndB)和(EndA> = StartB)

证明:
让ConditionA意味着DateRange A完全在DateRange B之后 _ |---- DateRange A ------| |---Date Range B -----| _
  (如果StartA > EndB

,则为真

让ConditionB意味着DateRange A完全在DateRange B之前 |---- DateRange A -----| _ _ |---Date Range B ----|
 (如果EndA < StartB

,则为真

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

现在De Morgan's laws之一说:

Not (A Or B)&lt; =&gt; Not A And Not B

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


注意:这包括边缘完全重叠的条件。如果你想排除它,
>=运算符更改为>,将<=更改为<


注2。感谢@Baodad,请参阅this blog,实际重叠次数最少:
  {endA-startAendA - startBendB-startAendB - startB}

(StartA <= EndB) and (EndA >= StartB) (StartA <= EndB) and (StartB <= EndA)


注3。感谢@tomosius,更短的版本是:
DateRangesOverlap = max(start1, start2) < min(end1, end2)
这实际上是更长实现的语法快捷方式,其中包括额外的检查以验证开始日期是在endDates之前还是之前。从上面得出这个:

如果开始日期和结束日期可能不正常,即,如果startA > endAstartB > endB可能,那么您还必须检查它们是否有序,这意味着您有添加两个额外的有效性规则:
(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB) 或:
(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB) 或者,
(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB)) 或:
(Max(StartA, StartB) <= Min(EndA, EndB)

但是为了实现Min()Max(),你必须编码,(使用C三元语言来表示简洁性),: (StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)

答案 1 :(得分:359)

我认为,如果出现以下两个范围重叠就足够了:

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

答案 2 :(得分:100)

本文Time Period Library for .NET通过枚举 PeriodRelation 描述了两个时间段的关系:

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

enter image description here

答案 3 :(得分:72)

关于时间关系(或其他任何区间关系)的推理,请考虑Allen's Interval Algebra。它描述了两个间隔相对于彼此可能具有的13种可能的关系。您可以找到其他参考文献 - “Allen Interval”似乎是一个可操作的搜索词。您还可以在Snodgrass的Developing Time-Oriented Applications in SQL(PDF在线提供的PDF)以及Date,Darwen和Lorentzos Temporal Data and the Relational Model(2002)或Time and Relational Theory: Temporal Databases in the Relational Model and SQL(2014年;有效的第二个)中找到有关这些操作的信息。 TD&amp; RM版。)


简短(ish)答案是:给定两个日期间隔AB,其中包含.start.end以及约束.start <= .end,然后是两个间隔重叠如果:

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

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


ErikE评论:

  

如果算上有趣的话,你只能获得13分......当我发疯的时候,我可以得到“15个可能有两个间隔的关系”。通过合理的计数,我只得到6,如果你抛出关心A或B是否先出现,我只得到三个(没有交叉,部分交叉,一个完全在另一个内)。 15是这样的:[之前:之前,开始,之内,之后,之后],[开始:开始,内部,结束,之后],[内部:内部,结束,之后],[结束:结束,之后],[后:后。

我认为你不能把这两个条目计算在:之前'和'之后:之后'。如果你把一些关系等同于它们的反转,我可以看到7个条目(参见引用的维基百科URL中的图表;它有7个条目,其中6个具有不同的反转,等于没有明显的反转)。三个是否合理取决于您的要求。

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

答案 4 :(得分:26)

如果还应计算重叠本身,则可以使用以下公式:

overlap = max(0, min(EndDate1, EndDate2) - max(StartDate1, StartDate2))
if (overlap > 0) { 
    ...
}

答案 5 :(得分:16)

通过确保特定范围更早开始,可以大大简化所有基于范围相互关联来检查多种条件的解决方案!确保第一个范围通过在必要时预先交换范围来提前(或同时)开始。

然后,如果其他范围开始小于或等于第一个范围结束(如果范围包含,包含开始和结束时间)或小于(如果范围包括开始和排除),则可以检测重叠结束)。

假设两端都是包容性的,那么只有四种可能性,其中一种是不重叠的:

|----------------------|        range 1
|--->                           range 2 overlap
 |--->                          range 2 overlap
                       |--->    range 2 overlap
                        |--->   range 2 no overlap

范围2的端点不会进入。所以,在伪代码中:

def doesOverlap (r1, r2):
    if r1.s > r2.s:
        swap r1, r2
    if r2.s > r1.e:
        return false
    return true

这可以简化为:

def doesOverlap (r1, r2):
    if r1.s > r2.s:
        swap r1, r2
    return r2.s <= r1.e

如果范围在开头是包含的,而在结尾是独占的,则只需在第二个>语句中将>=替换为if(对于第一个代码段:in第二个代码段,您使用<而不是<=):

|----------------------|        range 1
|--->                           range 2 overlap
 |--->                          range 2 overlap
                       |--->    range 2 no overlap
                        |--->   range 2 no overlap

您极大地限制了必须进行的检查次数,因为通过确保范围1在范围2之后永远不会开始,您可以提前删除一半的问题空间。

答案 6 :(得分:13)

这是使用JavaScript的另一种解决方案。我的解决方案的特色:

  • 将空值处理为无穷大
  • 假设下限是包含的,上限是独占的。
  • 附带一系列测试

测试基于整数,但由于JavaScript中的日期对象具有可比性,因此您也可以输入两个日期对象。或者你可以投入毫秒时间戳。

代码:

/**
 * Compares to comparable objects to find out whether they overlap.
 * It is assumed that the interval is in the format [from,to) (read: from is inclusive, to is exclusive).
 * A null value is interpreted as infinity
 */
function intervalsOverlap(from1, to1, from2, to2) {
    return (to2 === null || from1 < to2) && (to1 === null || to1 > from2);
}

试验:

describe('', function() {
    function generateTest(firstRange, secondRange, expected) {
        it(JSON.stringify(firstRange) + ' and ' + JSON.stringify(secondRange), function() {
            expect(intervalsOverlap(firstRange[0], firstRange[1], secondRange[0], secondRange[1])).toBe(expected);
        });
    }

    describe('no overlap (touching ends)', function() {
        generateTest([10,20], [20,30], false);
        generateTest([20,30], [10,20], false);

        generateTest([10,20], [20,null], false);
        generateTest([20,null], [10,20], false);

        generateTest([null,20], [20,30], false);
        generateTest([20,30], [null,20], false);
    });

    describe('do overlap (one end overlaps)', function() {
        generateTest([10,20], [19,30], true);
        generateTest([19,30], [10,20], true);

        generateTest([10,20], [null,30], true);
        generateTest([10,20], [19,null], true);
        generateTest([null,30], [10,20], true);
        generateTest([19,null], [10,20], true);
    });

    describe('do overlap (one range included in other range)', function() {
        generateTest([10,40], [20,30], true);
        generateTest([20,30], [10,40], true);

        generateTest([10,40], [null,null], true);
        generateTest([null,null], [10,40], true);
    });

    describe('do overlap (both ranges equal)', function() {
        generateTest([10,20], [10,20], true);

        generateTest([null,20], [null,20], true);
        generateTest([10,null], [10,null], true);
        generateTest([null,null], [null,null], true);
    });
});

使用karma&amp; jasmine&amp; PhantomJS运行时的结果:

  

PhantomJS 1.9.8(Linux):20次成功执行20次(0.003秒/0.004秒)

答案 7 :(得分:8)

我愿意

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

答案 8 :(得分:7)

enter image description here

以下是实现魔术的代码:

 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 - &gt; 1启动
  • B - &gt; 1结束
  • C - &gt; 2开始
  • D - &gt; 2End

证明?查看此测试console code gist

答案 9 :(得分:7)

这是我在 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));
}

答案 10 :(得分:6)

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

----------------------|-------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.
) 

答案 11 :(得分:5)

这是我使用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;

答案 12 :(得分:3)

  

最简单的

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

- (void)rotateButton:(UIButton*)button {
    button.transform = CGAffineTransformMakeRotation(M_PI);
}

java.time&amp; ThreeTen-EXTRA

业务中最好的是Java 8及更高版本中内置的java.time框架。再添加一个ThreeTen-Extra项目,该项目补充了java.time和其他类,特别是我们需要的Interval类。

对于此问题的someInterval.overlaps( anotherInterval ) 标记,这两个项目的源代码可用于其他语言(请注意其许可证)。

language-agnostic

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

java.time.Instant

创建Instant start = Instant.parse( "2016-01-01T00:00:00Z" ); Instant stop = Instant.parse( "2016-02-01T00:00:00Z" ); 来表示该时间范围。

Interval

我们还可以定义Interval interval_A = Interval.of( start , stop ); ,其中包含起始时刻加上Duration

Interval

比较重叠测试很容易。

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

您可以将Interval与其他IntervalInstant进行比较:

所有这些都使用Boolean overlaps = interval_A.overlaps( interval_B ); 方法来定义开头包含的时间跨度,结尾是独占

答案 13 :(得分:2)

由于针对不同的语言和环境有多种答案,这里是标准 ANSI SQL 的一种。

在标准 SQL 中,它就像一样简单

(StartDate1, EndDate1) overlaps (StartDate2, EndDate2)

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

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


在 PostgreSQL 中,使用 date ranges

也很容易测试包含
daterange(StartDate1, EndDate1) @> daterange(StartDate2, EndDate2)

如果第二个范围完全包含在第一个范围内(不同于“重叠”),则上述返回 true

答案 14 :(得分:2)

这是@ charles-bretana excellent answer的扩展。

然而,答案并没有区分开放,封闭和半开(或半封闭)的间隔。

案例1 :A,B是关闭间隔

A = [StartA, EndA]
B = [StartB, EndB]

                         [---- DateRange A ------]   (True if StartA > EndB)
[--- Date Range B -----]                           


[---- DateRange A -----]                             (True if EndA < StartB)
                         [--- Date Range B ----]

重叠iff:(StartA <= EndB) and (EndA >= StartB)

案例2 :A,B是开放时间间隔

A = (StartA, EndA)
B = (StartB, EndB)

                         (---- DateRange A ------)   (True if StartA >= EndB)
(--- Date Range B -----)                           

(---- DateRange A -----)                             (True if EndA <= StartB)
                         (--- Date Range B ----)

重叠iff:(StartA < EndB) and (EndA > StartB)

案例3 :A,B右开

A = [StartA, EndA)
B = [StartB, EndB)

                         [---- DateRange A ------)   (True if StartA >= EndB) 
[--- Date Range B -----)                           

[---- DateRange A -----)                             (True if EndA <= StartB)
                         [--- Date Range B ----)

重叠条件:(StartA < EndB) and (EndA > StartB)

案例4 :A,B左开

A = (StartA, EndA]
B = (StartB, EndB]

                         (---- DateRange A ------]   (True if StartA >= EndB)
(--- Date Range B -----]                           

(---- DateRange A -----]                             (True if EndA <= StartB)
                         (--- Date Range B ----]

重叠条件:(StartA < EndB) and (EndA > StartB)

案例5 :右开,B关闭

A = [StartA, EndA)
B = [StartB, EndB]

                         [---- DateRange A ------)    (True if StartA > EndB)
[--- Date Range B -----]                           


[---- DateRange A -----)                              (True if EndA <= StartB)  
                         [--- Date Range B ----]

重叠条件:(StartA <= EndB) and (EndA > StartB)

<强>等...

最后,两个重叠间隔的一般条件是

(StartA&lt; EndB)和(EndA&gt; StartB)

每当在两个包含的端点之间进行比较时,将严格的不等式转换为非严格的不等式。

答案 15 :(得分:2)

答案对我来说太简单了所以我创建了一个更通用的动态SQL语句,它检查一个人是否有任何重叠日期。

SELECT DISTINCT T1.EmpID
FROM Table1 T1
INNER JOIN Table2 T2 ON T1.EmpID = T2.EmpID 
    AND T1.JobID <> T2.JobID
    AND (
        (T1.DateFrom >= T2.DateFrom AND T1.dateFrom <= T2.DateTo) 
        OR (T1.DateTo >= T2.DateFrom AND T1.DateTo <= T2.DateTo)
        OR (T1.DateFrom < T2.DateFrom AND T1.DateTo IS NULL)
    )
    AND NOT (T1.DateFrom = T2.DateFrom)

答案 16 :(得分:2)

如果您使用的日期范围尚未结束(仍在进行中),例如没有设置 endDate =&#39; 0000-00-00&#39;你不能使用BETWEEN因为0000-00-00不是一个有效的日期!

我使用了这个解决方案:

(Startdate BETWEEN '".$startdate2."' AND '".$enddate2."')  //overlap: starts between start2/end2
OR (Startdate < '".$startdate2."' 
  AND (enddate = '0000-00-00' OR enddate >= '".$startdate2."')
) //overlap: starts before start2 and enddate not set 0000-00-00 (still on going) or if enddate is set but higher then startdate2

如果startdate2更高,则enddate没有重叠!

答案 17 :(得分:1)

在我看来,最简单的方法是比较EndDate1是否在StartDate2之前,EndDate2在StartDate1之前。

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

答案 18 :(得分:1)

使用Java util.Date,这就是我所做的。

    public static boolean checkTimeOverlaps(Date startDate1, Date endDate1, Date startDate2, Date endDate2)
    {
        if (startDate1 == null || endDate1 == null || startDate2 == null || endDate2 == null)
           return false;

        if ((startDate1.getTime() <= endDate2.getTime()) && (startDate2.getTime() <= endDate1.getTime()))
           return true;

        return false;
    }

答案 19 :(得分:1)

在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

答案 20 :(得分:1)

我遇到的情况是我们有日期而不是日期时间,日期可能只在开始/结束时重叠。示例如下:

enter image description here

(绿色是当前间隔,蓝色块是有效间隔,红色是重叠间隔)。

我改编了Ian Nelson对以下解决方案的回答:

$('.ui.dimmer.modals').addClass('inverted');

这匹配所有重叠情况,但忽略允许的重叠情况。

答案 21 :(得分:1)

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

答案 22 :(得分:1)

@Bretana给出的数学解决方案很好但忽略了两个具体细节:

  1. 关闭或半开区间的方面
  2. 空间隔
  3. 关于间隔边界的闭合或开放状态,@布雷纳纳的解决方案有效用于关闭间隔

      

    (StartA&lt; = EndB)和(EndA&gt; = StartB)

    可以将重写为半开区间改为:

      

    (StartA&lt; EndB)和(EndA&gt; StartB)

    这种校正是必要的,因为根据定义,开放区间边界不属于区间的值范围。

    关于空间隔,嗯,这里上面显示的关系不成立。根据定义,不包含任何有效值的空间隔必须作为特殊情况处理。我通过这个例子在我的Java时间库Time4J中演示它:

    MomentInterval a = MomentInterval.between(Instant.now(), Instant.now().plusSeconds(2));
    MomentInterval b = a.collapse(); // make b an empty interval out of a
    
    System.out.println(a); // [2017-04-10T05:28:11,909000000Z/2017-04-10T05:28:13,909000000Z)
    System.out.println(b); // [2017-04-10T05:28:11,909000000Z/2017-04-10T05:28:11,909000000Z)
    

    前方括号“[”表示关闭开始,而最后一个括号“)”表示开放结束。

    System.out.println(
          "startA < endB: " + a.getStartAsInstant().isBefore(b.getEndAsInstant())); // false
    System.out.println(
          "endA > startB: " + a.getEndAsInstant().isAfter(b.getStartAsInstant())); // true
    
    System.out.println("a overlaps b: " + a.intersects(b)); // a overlaps b: false
    

    如上所示,空间隔违反了上面的重叠条件(特别是startA&lt; endB),因此Time4J(以及其他库)也必须将其作为特殊边缘情况处理,以保证任意间隔的重叠没有空间隔。当然,日期间隔(默认情况下在Time4J中关闭,但也可以半开,如空日期间隔)以类似的方式处理。

答案 23 :(得分:1)

这是一个可以在本地使用的通用方法。

    // Takes a list and returns all records that have overlapping time ranges.
    public static IEnumerable<T> GetOverlappedTimes<T>(IEnumerable<T> list, Func<T, bool> filter, Func<T,DateTime> start, Func<T, DateTime> end)
    {
        // Selects all records that match filter() on left side and returns all records on right side that overlap.
        var overlap = from t1 in list
                      where filter(t1)
                      from t2 in list
                      where !object.Equals(t1, t2) // Don't match the same record on right side.
                      let in1 = start(t1)
                      let out1 = end(t1)
                      let in2 = start(t2)
                      let out2 = end(t2)
                      where in1 <= out2 && out1 >= in2
                      let totover = GetMins(in1, out1, in2, out2)
                      select t2;

        return overlap;
    }

    public static void TestOverlap()
    {
        var tl1 = new TempTimeEntry() { ID = 1, Name = "Bill", In = "1/1/08 1:00pm".ToDate(), Out = "1/1/08 4:00pm".ToDate() };
        var tl2 = new TempTimeEntry() { ID = 2, Name = "John", In = "1/1/08 5:00pm".ToDate(), Out = "1/1/08 6:00pm".ToDate() };
        var tl3 = new TempTimeEntry() { ID = 3, Name = "Lisa", In = "1/1/08 7:00pm".ToDate(), Out = "1/1/08 9:00pm".ToDate() };
        var tl4 = new TempTimeEntry() { ID = 4, Name = "Joe", In = "1/1/08 3:00pm".ToDate(), Out = "1/1/08 8:00pm".ToDate() };
        var tl5 = new TempTimeEntry() { ID = 1, Name = "Bill", In = "1/1/08 8:01pm".ToDate(), Out = "1/1/08 8:00pm".ToDate() };
        var list = new List<TempTimeEntry>() { tl1, tl2, tl3, tl4, tl5 };
        var overlap = GetOverlappedTimes(list, (TempTimeEntry t1)=>t1.ID==1, (TempTimeEntry tIn) => tIn.In, (TempTimeEntry tOut) => tOut.Out);

        Console.WriteLine("\nRecords overlap:");
        foreach (var tl in overlap)
            Console.WriteLine("Name:{0} T1In:{1} T1Out:{2}", tl.Name, tl.In, tl.Out);
        Console.WriteLine("Done");

        /*  Output:
            Records overlap:
            Name:Joe T1In:1/1/2008 3:00:00 PM T1Out:1/1/2008 8:00:00 PM
            Name:Lisa T1In:1/1/2008 7:00:00 PM T1Out:1/1/2008 9:00:00 PM
            Done
         */
    }

答案 24 :(得分:0)

将问题分解为案例然后处理每个案例

“两个日期范围相交”的情况由两种情况涵盖 - 第一个日期范围在第二个日期范围内开始,或者第二个日期范围在第一个日期范围内开始。

答案 25 :(得分:0)

def if_lives_overlap(s1, s2):
    """
    https://stackoverflow.com/a/325964/827391
        5   10    15  20
        ----------------
    s1: -----
    s2:           -----
    >>> if_lives_overlap(s1={'start': datetime(2020, 1, 5),
    ...                       'end': datetime(2020, 1, 10)},
    ...                  s2={'start': datetime(2020, 1, 15),
    ...                       'end': datetime(2020, 1, 20)})
    False


    s1:           -----
    s2: -----
    >>> if_lives_overlap(s1={'start': datetime(2020, 1, 15),
    ...                       'end': datetime(2020, 1, 20)},
    ...                  s2={'start': datetime(2020, 1, 5),
    ...                       'end': datetime(2020, 1, 10)})
    False

    s1: ----------
    s2:      ----------
    >>> if_lives_overlap(s1={'start': datetime(2020, 1, 5),
    ...                       'end': datetime(2020, 1, 15)},
    ...                  s2={'start': datetime(2020, 1, 10),
    ...                       'end': datetime(2020, 1, 20)})
    True

    s1:      ----------
    s2: ----------
    >>> if_lives_overlap(s1={'start': datetime(2020, 1, 10),
    ...                       'end': datetime(2020, 1, 20)},
    ...                  s2={'start': datetime(2020, 1, 5),
    ...                       'end': datetime(2020, 1, 15)})
    True


    s1: ---------------
    s2:      -----
    >>> if_lives_overlap(s1={'start': datetime(2020, 1, 5),
    ...                       'end': datetime(2020, 1, 20)},
    ...                  s2={'start': datetime(2020, 1, 10),
    ...                       'end': datetime(2020, 1, 15)})
    True

    s1:      -----
    s2: ---------------
    >>> if_lives_overlap(s1={'start': datetime(2020, 1, 10),
    ...                       'end': datetime(2020, 1, 15)},
    ...                  s2={'start': datetime(2020, 1, 5),
    ...                       'end': datetime(2020, 1, 20)})
    True
    """

    return (s1['start'] <= s2['end']) and (s1['end'] >= s2['start'])

答案 26 :(得分:0)

我发现了另一种非常简单的方法。如果daterange1的开始日期和结束日期早于daterange2的开始日期,或者daterange1的开始日期和结束日期落在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())));
}

答案 27 :(得分:0)

一个容易记住的解决方案是
min(ends)>max(starts)

答案 28 :(得分:0)

这是另一个使用 momentjs 的简短答案:

-isystem

答案基于上述答案,但有所缩短。

答案 29 :(得分:0)

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

  

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

条件是:

如果@StartDate位于existingStartDate之前且位于existingEndDat之后,那么我们可以说@StartDate位于现有日期范围的中间位置,因此我们可以得出结论重叠

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

如果@StartDate落后existingStartDate@EndDate位于existingStartDate之前,我们可以说它会重叠

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

如果@StartDate落后于existingStartDate@EndDate位于existingEndDate之前,我们可以断定所提供的日期范围会吞噬现有的日期范围,从而重叠

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

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

答案 30 :(得分:0)

if (StartDate1 > StartDate2) swap(StartDate, EndDate);

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

答案 31 :(得分:0)

简易解决方案:

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

答案 32 :(得分:0)

你可以试试这个:

//custom date for example
$d1 = new DateTime("2012-07-08");
$d2 = new DateTime("2012-07-11");
$d3 = new DateTime("2012-07-08");
$d4 = new DateTime("2012-07-15");

//create a date period object
$interval = new DateInterval('P1D');
$daterange = iterator_to_array(new DatePeriod($d1, $interval, $d2));
$daterange1 = iterator_to_array(new DatePeriod($d3, $interval, $d4));
array_map(function($v) use ($daterange1) { if(in_array($v, $daterange1)) print "Bingo!";}, $daterange);

答案 33 :(得分:0)

下面的查询给出了我提供的日期范围(开始和结束日期与我的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'))

答案 34 :(得分:0)

对于红宝石我也发现了这个:

class Interval < ActiveRecord::Base

  validates_presence_of :start_date, :end_date

  # Check if a given interval overlaps this interval    
  def overlaps?(other)
    (start_date - other.end_date) * (other.start_date - end_date) >= 0
  end

  # Return a scope for all interval overlapping the given interval, including the given interval itself
  named_scope :overlapping, lambda { |interval| {
    :conditions => ["id <> ? AND (DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", interval.id, interval.end_date, interval.start_date]
  }}

end

在这里找到了很好的解释 - &gt; http://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-ruby-or-rails

答案 35 :(得分:0)

这是我的解决方案,当值不重叠时返回true:

X START 1 Y END 1

开始2 B结束2

TEST1: (X <= A || X >= B)
        &&
TEST2: (Y >= B || Y <= A) 
        && 
TEST3: (X >= B || Y <= A)


X-------------Y
    A-----B

TEST1:  TRUE
TEST2:  TRUE
TEST3:  FALSE
RESULT: FALSE

---------------------------------------

X---Y
      A---B

TEST1:  TRUE
TEST2:  TRUE
TEST3:  TRUE
RESULT: TRUE

---------------------------------------

      X---Y
A---B

TEST1:  TRUE
TEST2:  TRUE
TEST3:  TRUE
RESULT: TRUE

---------------------------------------

     X----Y
A---------------B

TEST1:  FALSE
TEST2:  FALSE
TEST3:  FALSE
RESULT: FALSE

答案 36 :(得分:-1)

一个对我有用的简洁公式

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