多次重叠日期范围

时间:2015-03-27 20:49:41

标签: ios objective-c date nsdate nsdatecomponents

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

[]表示范围

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

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

问题:

  • 我已将spanStart设置为20:00
  • 我已将spanStop设置为08:00
  • 我已将userRangeStart设置为07:00
  • 我已将userRangeStop设置为01:00,(比userStartRange晚了18个小时)

通过测试不同的组合,我设法得到的最好的是一小时之外。问题是如果userRangeStart和userRangeStop延伸了几天,我就无法获得第一天以外的重叠时间。 如何才能使这种重叠检测连续进行?

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

更新

看起来像这样:

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

或者这个:

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

或者这个:

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

或其他任何事情。没有规则,所以我需要一个无论设置如何工作的功能

1 个答案:

答案 0 :(得分:1)

对我来说,你是在想这个。

NSDates实际上只是一段时间以来的几秒钟。 (2001年1月1日午夜,UTC)。

您可以使用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。

编辑:

我正在思考一个结构&#34; span&#34;包含开始日期和结束日期为NSTimeInterval值(双精度)

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

-[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,您也​​可以使它工作。您只需要将所有对span开头和结尾的引用更改为[spanA.start timeIntervalSinceReferenceDate]

之类的代码

编辑#2:

还有另一组案例,其中一个或两个端点匹配。我只是改变了上面的逻辑,使所有的比较包括平等。我认为这样可以处理所有情况,但请亲自检查一下。