简体   繁体   中英

Counting coverage of moment-range with multiple other ranges

I have a set of moment-range objects:

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)

So we have some adjacent ranges, but none that overlap . I also have a primary range:

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

The end goal is to create some function that checks the coverage of the primary range using the other ranges:

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

I know ranges are time (ms) and not day based, but I'd ideally convert to that somewhere in my function later.

Note that it does not double-count 2018-10-15 . The primary solution I considered for this was to loop through each of the ranges and, if they are adjacent or neighboring, use the add method with {adjacent:true} to merge the ranges into the largest possible chunks. This still likely leaves me with some gaps, and finding the total number of days within the primary range will need to be done with brute force (iterate through each day of primary to see if it exists within any of the secondary ranges.

Another tricky part is if one of the secondary ranges starts/ends outside of the primary range (maybe 2018-09-25 -> 2018-10-02 ).

Am I missing some documented method that would help me achieve this? Maybe some clever usage of contains or within ?

Thank you

Edit: This discussion seems on-topic, I will report back after I've experimented with their subtract example to see if it works here.

This algorithm works for the example you posted:

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
  }))
}

Here is an example using the dates you posted in your question:

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

and the result is:

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

which is exactly what I would expect.

NOTE: I know you are dealing with dates instead of times. If your input dates are moment values with 0-time and utc() note there is another issue in moment-range that loses the timezone information of the inputs which may affect your date results. You can work around it by mapping the result with a function like:

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

ie

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM