多次重叠日期范围

overlapping date range multiple times

我需要查看给定日期范围与其他范围重叠的小时数,如下所示:

[ ] 表示范围

    [<<-07:00->>                            <<-(next day)01:00->>]
[<<-00:00->>    <<-08:00->>] [<<-20:00->><<-23:59->>][<<-00:00->> <<-08:00->>]

第一行是用户提供的日期范围。在这个例子中,答案应该是重叠 6 小时,而剩余的 12 小时 不重叠。

这是我当前的代码:

    // The float that represents the hours overlapping
float overlappingHours = 0.0;

// Calculate overlapping interval
NSDate *overlapFrom = [spanStart laterDate:userRangeStart];
NSDate *overlapTo = [spanStop earlierDate:userRangeStop];

// Calculate new salary
if ([overlapFrom compare:overlapTo] > 0) {
    // Date ranges do not overlap
} else {
    // Date ranges do not overlap
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *dateComponents = [calendar components:NSCalendarUnitHour fromDate:overlapFrom toDate:overlapTo options:0];
    overlappingHours = [dateComponents hour];
}

通过为所提供的四个日期提供不同的组合,我得到了不同的结果。例如,如果我省略日期而只包括时间等。

问题:

通过测试不同的组合,我设法获得的最佳成绩是一小时的路程。问题是,如果 userRangeStart 和 userRangeStop 跨越几天,我无法设法获得第一天以外的重叠时间。 我怎样才能使这种重叠检测连续进行?

我真的坚持了这一点,非常感谢您的帮助! 埃里克

更新:

它可能看起来像这样:

a---------------------------------------b
           c-----------------d

或者这样:

           a-------------------------b
c--------------------d          e-------------f

或者这样:

                       a----------------------b
c------------------d           e-------f

或者其他任何东西。没有规则,所以我需要一个无论设置如何都能正常工作的函数

我觉得你想多了。

NSDates 实际上只是从某个时刻开始的秒数。 (UTC 时间 2001 年 1 月 1 日午夜)。

您可以使用方法 timeIntervalSinceReferenceDate 将任何 NSDate 转换为秒。

当你这样做时,你的日期是浮点数,以秒为单位。然后你就可以自由地做任何你想做的数学了。

这样处理,2 个日期范围是时间线上的线段。计算日期范围之间的重叠变得简单的逻辑和浮点运算。

您的结果将以秒为单位,因此只需除以 3600 即可得到以小时为单位的重叠。

假设我有一个从 a 到 b 的日期范围和另一个从 c 到 d 的日期范围。

它们是 NSDates 或 NSTimeInterval 值。两者可以使用 timeIntervalSinceReferenceDate 互换。

说范围c:d晚于范围a:b,并且c:d的开头与a:b

的结尾重叠

在时间轴上可视化,左侧较旧,右侧较新:

a                b
         c             d

因此,如果 a、b、c 和 d 都是 NSTimeInterval 值,则日期的重叠将只是 b-c。那将是几秒钟的重叠。 (b-c)/3600 会给你重叠的小时数和小时数。

根本不需要使用 NSCalendar 和 NSTimeInterval。

编辑:

我正在考虑一个包含开始日期和结束日期作为 NSTimeInterval 值(双精度)的结构“span”

有一些简单的方法可以将日期转换为时间间隔

-[NSDate timeIntervalSinceReferenceDate]

和日期的时间间隔

+[NSDate dateWithTimeIntervalSinceReferenceDate]

typedef struct 
{
  NSTimeInterval start;
  NSTimeInterval end;
} span;

跨度 a、b、c、d;

查看 2 个跨度是否重叠的方法:

+ (BOOL) span: (span)  spanA
  overlapsSpan: (span)  spanB;
{
  return
    //The spans overlap if spanB's start is inside spanA
    (spanB.start > spanA.start && spanB.start < spanA.en)
  ||
    //or if spanB's END is inside spanA
    (spanB.end > spanA.start && spanB.end < spanA.end)
  ||
    //or if spanA's start is inside spanB
    (spanA.start > spanB.start && spanA.start < spanB.end);
}

以及计算重叠的方法(以秒为单位)

+ (NSTimeInterval) ovelapFromSpan: (span)  spanA
    overlapsSpan: (span)  spanB
{
  BOOL bStartInsideA = 
    spanB.start >= spanA.start && spanB.start <= spanA.end;
  BOOL bEndInsideA = 
    spanB.end >= spanA.start && spanB.end <= spanA.end;

  BOOL aStartInsideB = 
    spanA.start >= spanB.start && spanA.start <= spanB.end;
  BOOL aEndInsideB = 
    spanA.end >= spanB.start && spanA.end <= spanB.end;

  //  ----A----
  //        ----B----
  if (bStartInsideA && !bEndInsideA)
    return spanA.end - spanB.end;

  //        ----A----
  //  ----B----
  else if (bEndInsideA && !bStartInsideA)
    return spanB.end - spanA.start;

  //  ----A----
  //    --B--
  else if (bStartInsideA  && bEndInsideA )
    return spanB.end - spanB.start;

  //    --A--
  //  ----B----
  else if (aStartInsideB  && aEndInsideB )
    return spanA.end - spanA.start;

  else return 0; //No overlap
}

如果您的 span 结构包含 NSDates,您也​​可以让它工作。您只需要将所有对跨度开始和结束的引用更改为 [spanA.start timeIntervalSinceReferenceDate]

之类的代码

编辑#2:

还有另一组情况,其中一个或两个端点匹配。我只是更改了上面的逻辑,使所有比较都包含相等性。我认为这可以解决所有情况,但你自己检查一下。