多次重叠日期范围
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];
}
通过为所提供的四个日期提供不同的组合,我得到了不同的结果。例如,如果我省略日期而只包括时间等。
问题:
- 我已将 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
或者其他任何东西。没有规则,所以我需要一个无论设置如何都能正常工作的函数
我觉得你想多了。
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:
还有另一组情况,其中一个或两个端点匹配。我只是更改了上面的逻辑,使所有比较都包含相等性。我认为这可以解决所有情况,但你自己检查一下。
我需要查看给定日期范围与其他范围重叠的小时数,如下所示:
[ ] 表示范围
[<<-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
或者其他任何东西。没有规则,所以我需要一个无论设置如何都能正常工作的函数
我觉得你想多了。
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:
还有另一组情况,其中一个或两个端点匹配。我只是更改了上面的逻辑,使所有比较都包含相等性。我认为这可以解决所有情况,但你自己检查一下。