使用多个其他范围计算时刻范围的覆盖范围

时间:2018-06-08 07:10:25

标签: javascript momentjs moment-range

我有一组moment-range个对象:

a = range(2018-10-01 -> 2018-10-05)
b = range(2018-10-10 -> 2018-10-15)
c = range(2018-10-15 -> 2018-10-20)
d = range(2018-10-21 -> 2018-10-25)

所以我们有一些adjacent范围,但没有overlap。我也有一个主要范围:

primary = range(2018-10-01 -> 2018-10-31)

最终目标是创建一些功能,使用其他范围检查主要范围的覆盖范围:

coverage(primary, [a,b,c,d])
// returns 21
// (5 days + 6 days + 5 days + 5 days)

我知道范围是时间(ms)而不是基于日期,但我理想情况下会在以后的某个地方转换为。

请注意,它不会重复计算2018-10-15。我考虑的主要解决方案是循环遍历每个范围,如果它们相邻或相邻,则使用add方法和{adjacent:true}将范围合并到最大可能的块中。这仍然可能让我留下一些空白,并且需要在蛮力范围内找到主要范围内的总天数(迭代primary的每一天以查看它是否存在于任何次要范围内

另一个棘手的部分是,如果其中一个次要范围在主要范围之外开始/结束(可能是2018-09-25 -> 2018-10-02)。

我是否遗漏了一些有助于我实现此目标的文档化方法?也许巧妙地使用containswithin

谢谢

修改:This discussion似乎是关于主题的,我会在我尝试了subtract示例之后向我们报告,看看它是否有用。

1 个答案:

答案 0 :(得分:0)

此算法适用于您发布的示例:

function subtractRanges (source, others) {
  if (!Array.isArray(source)) {
    source = [source]
  }
  return flatten(source.map(s => {
    return flatten(others).reduce((remaining, o) => {
      return flatten(remaining.map(r => r.subtract(o)))
    }, [s])
    return remaining
  }))
}

以下是使用您在问题中发布的日期的示例:

https://runkit.com/rocketraman/5b1aaf0bc454290012b9fc5a

结果是:

2018-10-05T00:00:00-04:00/2018-10-10T00:00:00-04:00
2018-10-20T00:00:00-04:00/2018-10-21T00:00:00-04:00
2018-10-25T00:00:00-04:00/2018-10-31T00:00:00-04:00

这正是我所期待的。

注意:我知道你正在处理日期而不是时间。如果您的输入日期是具有0时间和utc()的时刻值,则会在时间范围内another issue丢失输入的时区信息,这可能会影响您的日期结果。您可以通过使用以下函数映射结果来解决此问题:

function fixRangeIssue228 (range) {
  // workaround https://github.com/rotaready/moment-range/issues/228
  return moment.range(range.start.utc(), range.end.utc())
}

let result = subtractRanges(...).map(fixRangeIssue228)