确定两个date范围是否重叠

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

举一个例子,假设我们有由DateTimevariablesStartDate1EndDate1 StartDate2EndDate2

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

certificate:
让ConditionA表示DateRange A完全在DateRange B之后
_ |---- DateRange A ------| |---Date Range B -----| _
(如果StartA > EndB真)

让ConditionB表示DateRange A完全在DateRange B之前
|---- DateRange A -----| _ _ |---Date Range B ----|
(如果EndA < StartB真)

那么,如果不是一个正确的答案,
(如果一个范围既不完全相同,
也不是完全在另一个之前,那么它们必须重叠。)

现在德摩根的一个法律说:

Not (A Or B) <=> Not A And Not B

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


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


笔记2。 感谢@Baodad,看到这个博客 ,实际的重叠是最less的:
{ endA-startAendA - startBendB-startAendB - startB }

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


注3。 由于@tomosius,一个较短的版本读取:
DateRangesOverlap = max(start1, start2) < min(end1, end2)
对于什么是更长的实现,这实际上是一个语法快捷方式,其中包括额外的检查以validation开始date是否在结束date之前或之前。 从上面得出这个:

如果开始date和结束date可能无序,即,如果有可能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)

我相信只要说两个范围重叠就足够了:

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

本文的.NET时间库用枚举PeriodRelation描述了两个时间段的关系:

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

在这里输入图像描述

为了推理关于时间关系(或任何其他区间关系,请参阅),考虑Allen的区间代数 。 它描述了两个时间间隔可以相互关联的13种可能的关系。 你可以find其他的参考 – “艾伦间隔”似乎是一个有效的search术语。 您也可以在Snodgrass的SQL开发时间应用程序中find有关这些操作的信息(可在线获取PDF),以及Date,Darwen和Lorentzos 时间数据和关系模型 (2002)或时间和关系理论:时态数据库关系模型和SQL (2014;实际上是TD&RM的第二版)。


简短的(ish)答案是:给定两个date间隔AB其中包含组件.start.end以及约束.start <= .end ,则两个间隔重叠,如果:

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

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


ErikE评论:

如果你把事情搞得有趣的话,你只能得到13 …当我疯狂的时候,我可以得到“两个间隔可能有的15种可能的关系”。 通过明智的计算,我只能得到六个,如果你抛出A或B先到的关心,我只得到三个(没有相交,部分相交,完全在另一个之内)。 15开始是这样的:[before:before,start,within,end,after],[start:start,within,end,after],[within:within,end,after],[end:end,after]后:后。

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

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

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

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

所有的解决scheme,通过确保一个特定的范围提前开始,可以大大简化基于范围相互关联的多个条件的解决scheme 您可以确保第一个范围先于(或同时)开始,如果必要的话,先交换范围。

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

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

 |----------------------| 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语句中replace> with >= (对于第一个代码段:在第二个代码段中,您将使用<而不是<= ):

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

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

这是另一个使用JavaScript的解决scheme。 我的解决scheme的专长:

  • 将空值处理为无穷大
  • 假设下界是包含的,上界是排他的。
  • 附带一堆testing

testing是基于整数,但由于JavaScript中的date对象是可比较的,所以您可以只input两个date对象。 或者你可以扔在毫秒时间戳。

码:

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

testing:

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

结果当与业力和茉莉花&PhantomJS运行:

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

我知道这已经被标记为与语言无关,但是对于所有使用Java的人来说:不要重新发明轮子并使用Joda Time。

http://joda-time.sourceforge.net/api-release/org/joda/time/base/AbstractInterval.html#overlaps(org.joda.time.ReadableInterval

我会做

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

这里发布的解决scheme不适用于所有重叠范围…

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

我的工作解决scheme是:

 AND(
   (STARTDATE和ENDDATE之间的'start_date') - 迎合内部和结束date外部
  要么
   ('end_date'在STARTDATE和ENDDATE之间) - 迎合内部和开始date外部
  要么
   (STARTDATE在'start_date'和'end_date'之间) - 只有一个date在里面的外部范围需要。
 ) 

这是我的javascript解决scheme与moment.js:

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

如果您使用的date范围还没有结束(仍在进行)例如未设置endDate ='0000-00-00',您不能使用BETWEEN,因为0000-00-00是不是有效的date!

我使用这个解决scheme:

 (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,则没有重叠!

最简单的

最简单的方法是使用精心devise的专用图书馆进行date时间工作。

 someInterval.overlaps( anotherInterval ) 

java.time&ThreeTen-Extra

业务最好的是Java 8及更高版本中构build的java.time框架。 再加上ThreeTen-Extra项目来补充java.time和其他类,特别是我们需要的Interval类。

至于这个问题上与language-agnostic标签,两个项目的源代码都可以用于其他语言(介意他们的许可证)。

Interval

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

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

创build一个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 ) ); 

比较testing重叠很容易。

 Boolean overlaps = interval_A.overlaps( interval_B ); 

您可以将Interval与另一IntervalInstant进行比较:

  • abuts
  • contains
  • encloses
  • equals
  • isAfter
  • isBefore
  • overlaps

所有这些都使用Half-Open方法来定义一个时间跨度,其中开始是包容性的 ,结尾是排他性的

这是@ charles-bretana 杰出答案的延伸。

但答案并没有区分开放,封闭和半开放(或半封闭)区间。

案例1 :A,B是closures间隔

 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 :右开,Bclosures

 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 <🞐EndB)和(EndA>🞐StartB)

当两个端点之间进行比较时,🞐将严格的不平等变为非严格的不平等。

这是我在Java中的解决scheme,它也在无限的时间间隔上工作

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

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

  // 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 */ } 

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

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

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

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

@Bretana提供的math解决scheme是好的,但忽略了两个具体细节:

  1. closures或半开放的时间段
  2. 空的间隔

关于区间边界的closures或开放状态,@Bretana的解决scheme对于闭区间有效

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

可以重写为半开间隔

(StartA <EndB)和(EndA> 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 <endB),所以Time4J(和其他库)也必须将其作为特殊边缘情况来处理,以保证任意间隔与空间隔的重叠不存在。 当然,date时间间隔(在Time4J中默认closures,但也可以半开放,如空的date间隔)以类似的方式处理。

 if (StartDate1 > StartDate2) swap(StartDate, EndDate); (StartDate1 <= EndDate2) and (StartDate2 <= EndDate1); 

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

“两个date范围相交”的情况包含两种情况 – 第一个date范围在第二个范围内开始,或者第二个date范围在第一个范围内开始。

你可以试试这个:

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

This was my solution, it returns true when the values don't overlap:

X START 1 Y END 1

A START 2 B END 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 

For ruby I also found this:

 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 

Found it here with nice explaination -> http://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-ruby-or-rails

Below query gives me the ids for which the supplied date range (start and end dates overlaps with any of the dates (start and end dates) in my table_name

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

The answer is too simple for me so I have created a more generic dynamic SQL statement which checks to see if a person has any overlapping dates.

 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) 

I had a situation where we had dates instead of datetimes, and the dates could overlap only on start/end. 示例如下:

在这里输入图像描述

(Green is the current interval, blue blocks are valid intervals, red ones are overlapping intervals).

I adapted Ian Nelson's answer to the following solution:

  (startB <= startA && endB > startA) || (startB >= startA && startB < endA) 

This matches all overlap cases but ignores the allowed overlap ones.

Easy solution:

 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