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

例如,假设我们有由DateTime变量StartDate1到EndDate1和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);
    }

其他回答

如果您使用的日期范围尚未结束(仍在进行中),例如未设置endDate='0000-00-00'您不能使用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,则没有重叠!

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

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

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

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

本文《.NET时间段库》通过枚举PeriodRelation描述了两个时间段之间的关系:

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

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

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