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

Datetime 确定两个日期范围是否重叠,datetime,math,language-agnostic,Datetime,Math,Language Agnostic,给定两个日期范围,确定两个日期范围是否重叠的最简单或最有效的方法是什么 例如,假设我们有由日期时间变量StartDate1到EndDate1和StartDate2到EndDate2表示的范围。我认为,如果出现以下情况,可以说这两个范围重叠: (StartDate1 <= EndDate2) and (StartDate2 <= EndDate1) A.end >= B.start AND A.start <= B.end (开始日期1我愿意 StartDate1.Is

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


例如,假设我们有由日期时间变量
StartDate1
EndDate1
StartDate2
EndDate2

表示的范围。我认为,如果出现以下情况,可以说这两个范围重叠:

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
A.end >= B.start AND A.start <= B.end
(开始日期1我愿意

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);
    }
public static bool IsBetween(此日期时间值,左日期时间,右日期时间){
返回(值>左和值<右)| |(值<左和值>右);
}

我认为最简单的方法是比较EndDate1是否在StartDate2之前,EndDate2是否在StartDate1之前

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

(StartA=StartB)

证明:
让条件A表示日期范围A完全在日期范围B之后

_                        |---- DateRange A ------|
|---Date Range B -----|                          _
|---- DateRange A -----|                        _ 
_                          |---Date Range B ----|
(如果
StartA>EndB
,则为真)

条件B表示日期范围A完全在日期范围B之前

_                        |---- DateRange A ------|
|---Date Range B -----|                          _
|---- DateRange A -----|                        _ 
_                          |---Date Range B ----|
(如果
EndA
,则为真)

如果A和B都不为真,则存在重叠-
(如果一个范围既不完全在另一个范围之后,
也不完全是在对方之前,, 那么它们必须重叠。)

现在其中一位说:

非(A或B)
非A和非B

翻译成:
(StartA=StartB)


注意:这包括边完全重叠的情况。如果要排除此情况,

将< <代码> > <代码> >运算符> <代码> >代码> >代码> < P>为时间关系的推理(或任何其他的间隔关系,来此),考虑。它描述了两个区间之间可能存在的13种可能的关系。你可以找到其他的参考文献——“艾伦区间”。这似乎是一个有效的搜索词。你也可以在Snodgrass(网址为在线PDF)以及Date、Darwen和Lorentzos(2002)或(2014;实际上是TD&RM的第二版)中找到关于这些操作的信息



简短的(ish)答案是:给定两个日期间隔
A
B
,包含组件
.start
.end
以及约束
.start,这里有一个通用方法,可以在本地使用

    // 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
         */
    }
//获取一个列表并返回具有重叠时间范围的所有记录。
公共静态IEnumerable GetOverlappedTimes(IEnumerable列表、Func筛选器、Func开始、Func结束)
{
//选择左侧与filter()匹配的所有记录,并返回右侧重叠的所有记录。
var重叠=从列表中的t1开始
其中过滤器(t1)
从列表中的t2开始
其中!object.Equals(t1,t2)//不匹配右侧的相同记录。
让in1=开始(t1)
让出1=结束(t1)
让in2=开始(t2)
让出口2=结束(t2)
其中in1=in2
让totover=getmin(in1,out1,in2,out2)
选择t2;
返回重叠;
}
公共静态void TestOverlap()
{
var tl1=new-testimeentry(){ID=1,Name=“Bill”,In=“1/1/08 1:00pm”。ToDate(),Out=“1/1/08 4:00pm”。ToDate();
var tl2=new-testimeentry(){ID=2,Name=“John”,In=“1/1/08 5:00pm.ToDate(),Out=“1/1/08 6:00pm.ToDate();
var tl3=new-testimeentry(){ID=3,Name=“Lisa”,In=“1/1/08 7:00pm.ToDate(),Out=“1/1/08 9:00pm.ToDate();
var tl4=new-testimeentry(){ID=4,Name=“Joe”,In=“1/1/08 3:00pm.ToDate(),Out=“1/1/08 8:00pm.ToDate();
var tl5=new-testimeentry(){ID=1,Name=“Bill”,In=“1/1/08 8:01pm”。ToDate(),Out=“1/1/08 8:00pm”。ToDate();
var list=new list(){tl1,tl2,tl3,tl4,tl5};
var overlap=GetOverlappedTimes(list,(testimeentry t1)=>t1.ID==1,(testimeentry tIn)=>tIn.In,(testimeentry tOut)=>tOut.Out);
Console.WriteLine(\n记录重叠:);
foreach(重叠中的变量tl)
Console.WriteLine(“名称:{0}T1In:{1}T1Out:{2}”,tl.Name,tl.In,tl.Out);
控制台。写入线(“完成”);
/*输出:
记录重叠:
姓名:Joe T1In:1/1/2008 3:00:00 PM T1Out:1/1/2008 8:00:00 PM
姓名:Lisa T1In:1/1/2008 7:00:00 PM T1Out:1/1/2008 9:00:00 PM
多恩
*/
}

只要确保某个特定范围更早开始,就可以大大简化所有基于范围相互关系的位置检查多种条件的解决方案!如果需要,可以提前交换范围,以确保第一个范围更早开始(或同时开始)

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

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

|----------------------|        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
通过确保范围1不会在范围2之后开始,从而提前删除了一半的问题空间,从而大大限制了必须进行的检查的数量。

本文通过枚举period relation描述了两个时间段的关系:

// ------------------------------------------------------------------------
public enum PeriodRelation
{
    After,
    StartTouching,
    StartInside,
    InsideStartTouching,
    EnclosingStartTouching,
    Enclosing,
    EnclosingEndTouching,
    ExactMatch,
    Inside,
    InsideEndTouching,
    EndInside,
    EndTouching,
    Before,
} // enum PeriodRelation
function isOverlapping(startDate1, endDate1, startDate2, endDate2){ 
    return moment(startDate1).isSameOrBefore(endDate2) && 
    moment(startDate2).isSameOrBefore(endDate1);
}

如果重叠本身也需要计算,可以使用以下公式:

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

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

“两个日期范围相交”的情况包含在两个案例中-第一个日期范围在 ----------------------|-------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. )
//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);
(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
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");
            }
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
    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;
    }
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
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)
   (startB <= startA && endB > startA)
|| (startB >= startA && startB < endA)
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
A = [StartA, EndA]
B = [StartB, EndB]

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


[---- DateRange A -----]                             (True if EndA < StartB)
                         [--- Date Range 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 ----)
A = [StartA, EndA)
B = [StartB, EndB)

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

[---- DateRange A -----)                             (True if EndA <= StartB)
                         [--- Date Range 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 ----]
A = [StartA, EndA)
B = [StartB, EndB]

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


[---- DateRange A -----)                              (True if EndA <= StartB)  
                         [--- Date Range B ----]
 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));
function isOverlapping(startDate1, endDate1, startDate2, endDate2){ 
    return moment(startDate1).isSameOrBefore(endDate2) && 
    moment(startDate2).isSameOrBefore(endDate1);
}
(StartDate1, EndDate1) overlaps (StartDate2, EndDate2)
daterange(StartDate1, EndDate1) @> daterange(StartDate2, EndDate2)