1

I need to filter out any overlaps of start and end (moment.js) times of the following eg array of objects

[{ start: moment("2019-03-23T15:55:00.000"), end: moment("2019-03-23T16:55:00.000")},
 { start: moment("2019-03-23T14:40:00.000"), end: moment("2019-03-23T17:30:00.000")},
 { start: moment("2019-03-23T18:45:00.000"), end: moment("2019-03-23T19:45:00.000")},
 { start: moment("2019-03-23T17:10:00.000"), end: moment("2019-03-23T20:00:00.000")},
 { start: moment("2019-03-23T21:35:00.000"), end: moment("2019-03-23T22:35:00.000")},
 { start: moment("2019-03-23T19:15:00.000"), end: moment("2019-03-23T22:05:00.000")},
 { start: moment("2019-03-23T22:30:00.000"), end: moment("2019-03-23T23:30:00.000"),
}]

In the above example, the dates are all on the same day (03/23), so when looking at the times, I need to loop through each object and take the EARLIEST start time along with the LATEST end time with no overlap. I need a final array of alternating start, end, start, end ... times.

So, for the above example, I need to filter right down to just the following:

start: 14:40:00
end:   17:30:00
start: 18:45:00
end:   20:00:00
start: 21:35:00
end:   23:30:00

As you can see, the second start time only occurs after the first end time, and the final end time is basically the last available end time. The earliest start available in the whole set is 14:40:00 so it gets the first slot.

Further example is the start time 17:10:00; This start time is already covered by during the first start/end time, so it is ignored, however its paired end time of 20:00:00 is AFTER 19:45:00 so it replaces that end time in the cycle.

I hope this makes sense, please let me know if not.

What I have come up with still contains overlap and I'm not happy with it even if it worked.

times.forEach(time => {
    // start with the first object
    if (filtered.length === 0) {
        filtered.push({'start': time.start, 'end': time.end});
    }
    // if this start time is AFTER the prior end time, add it
    if (time.start.isAfter(filtered[filtered.length-1]['end'])) {
        filtered.push({'start': time.start, 'end': time.end});
    }
    if (time.start.isBefore(filtered[filtered.length-1]['end'])) {
        // replace the prior end time
        filtered[filtered.length-1]['end'] = time.end;
    }
});

As I said, clearly this is not great, but not sure how best to accomplish.

1 Answer 1

1
boundaries = [];
times.forEach (time => {
  boundaries.push ({type: "start", value: time.start});
  boundaries.push ({type: "end", value: time.end})
});

This will give you an array of boundaries looking like this:

[
  {type: "start", value: moment("2019-03-23T15:55:00.000")},
  {type: "end", value: moment("2019-03-23T16:55:00.000")},
  {type: "start", value: moment("2019-03-23T14:40:00.000")},
  {type: "end", value: moment("2019-03-23T17:30:00.000")},
  {type: "start", value: moment("2019-03-23T18:45:00.000")},
  {type: "end", value: moment("2019-03-23T19:45:00.000")},
  {type: "start", value: moment("2019-03-23T17:10:00.000")},
  {type: "end", value: moment("2019-03-23T20:00:00.000")},
  {type: "start", value: moment("2019-03-23T21:35:00.000")},
  {type: "end", value: moment("2019-03-23T22:35:00.000")},
  {type: "start", value: moment("2019-03-23T19:15:00.000")},
  {type: "end", value: moment("2019-03-23T22:05:00.000")},
  {type: "start", value: moment("2019-03-23T22:30:00.000")},
  {type: "end", value: moment("2019-03-23T23:30:00.000")}
]

Now sort this array by value and iterate over sorted array, counting how may "start" boundaries you passed minus how many "end" boundaries you passed. I.e. increment counter on every "start" boundary, and decrement it on every "end" boundary.

Every time counter goes from zero to non-zero, output filtered "start" boundary. Every time counter drops from non-zero to zero, output filtered "end" boundary.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.