Check if times overlap using moment?
Asked Answered
C

4

23

I have an array of [start_time, end_time] time ranges like so:

let timeSegments = [];
timeSegments.push(["02:00", "07:00"])
timeSegments.push(["03:00", "04:00"])

These time segments overlap, since 2AM - 7AM includes 3AM - 4AM

Likewise:

let timeSegments = [];
timeSegments.push(["14:00", "18:00"])
timeSegments.push(["15:00", "19:00"])

2PM to 6PM overlaps with 3PM to 7PM.

I'm using the momentjs library, and would like to know a way to determine if my timeSegments array contains any timeSegments that overlap? The timeSegments array can contain at most 10 [start_time, end_time] pairs. Thanks!

I'd just like to know if any segments overlap (true/false), I don't need to know which of the segments overlap etc.

Care answered 28/6, 2017 at 10:53 Comment(1)
So what do you want the result to be? true if any times in your array overlap? The overlapping times? The number of overlaps? Is your array always ordered as per your example (earliest->latest)Preposterous
H
26

You can sort timeSegments by start_time (using Array.prototype.sort) and iterate through the sorted list and check if end_time of the current timeSegment is greater than start_time of the next one.

If that happens, there is an overlap.

You can see an example of implementation below:

const checkOverlap = (timeSegments) => {
  if (timeSegments.length === 1) return false;

  timeSegments.sort((timeSegment1, timeSegment2) =>
    timeSegment1[0].localeCompare(timeSegment2[0])
  );

  for (let i = 0; i < timeSegments.length - 1; i++) {
    const currentEndTime = timeSegments[i][1];
    const nextStartTime = timeSegments[i + 1][0];

    if (currentEndTime > nextStartTime) {
      return true;
    }
  }

  return false;
};

const timeSegments1 = [
  ["03:00", "04:00"],
  ["02:00", "07:00"],
  ["12:00", "15:00"]
];

const timeSegments2 = [
  ["05:00", "07:00"],
  ["03:00", "04:00"],
  ["12:00", "15:00"]
];

console.log(checkOverlap(timeSegments1)); // prints true
console.log(checkOverlap(timeSegments2)); // prints false

Note that Array.prototype.sort mutates the array, performing the sort in-place. If you want to preserve the array passed to checkOverlap (which is, in general, a good practice), you can create a copy of timeSegments (using the spread syntax, for example):

const sortedTimeSegments = [...timeSegments].sort(...);
Hodman answered 28/6, 2017 at 11:0 Comment(0)
C
17

You can use moment-range plugin. You can create a range using moment.range function passing moment objects as input (parse your input strings using moment(String, String)). Then you can use the overlap method that checks if two ranges overlap.

Here a live sample:

window['moment-range'].extendMoment(moment);

let overlap = (timeSegments) => {
  let ret = false;
  let i = 0;
  while( !ret && i<timeSegments.length-1 ){
    let seg1 = timeSegments[i];
    let seg2 = timeSegments[i+1];
    let range1 = moment.range( moment(seg1[0], 'HH:mm'),  moment(seg1[1], 'HH:mm'));
    let range2 = moment.range( moment(seg2[0], 'HH:mm'),  moment(seg2[1], 'HH:mm'));
    if( range1.overlaps(range2) ){
      ret = true;
    }
    i++;
    
    return ret;
  }
};

let timeSegments = [];
timeSegments.push(["02:00", "07:00"])
timeSegments.push(["03:00", "04:00"])
console.log( overlap(timeSegments) ); // true

timeSegments = [];
timeSegments.push(["14:00", "18:00"])
timeSegments.push(["15:00", "19:00"])
console.log( overlap(timeSegments) ); // true

timeSegments = [];
timeSegments.push(["14:00", "18:00"])
timeSegments.push(["19:00", "21:00"])
console.log( overlap(timeSegments) ); // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-range/3.0.3/moment-range.min.js"></script>
Conrad answered 28/6, 2017 at 13:19 Comment(1)
If you have time ranges that cross midnight, split the range into two ranges (e.g. 22:00-04:00 would create 22:00-24:00 and 00:00-04:00) and do the overlaps check with the two.Hertzog
B
1

you can take the reference form the following code. I am using core JavaScript for this.

<script>
    var obj = [{ "from": "08:00", "to": "9:01" }, { "from": "18:45", "to": "19:00" }, { "from": "08:00", "to": "09:00" }, { "from": "12:00", "to": "14:00" }];
    obj = sortTime(obj);
    console.log(obj);
    if (checkoverlapping(obj)) {
        alert("yes time overlaps");
    } else {
        alert("No overlapping")
    }

    function sortTime(obj) {
        obj.sort(function (a, b) {
            KeyA = minuteValue(a.from);
            KeyB = minuteValue(b.from);

            if (KeyA < KeyB) return -1;
            else if (KeyA > KeyB) return 1;
            else {
                a = minuteValue(a.to);
                b = minuteValue(b.to);
                if (a < b) return -1;
                if (a > b) return 1;
                return 0
            }
        })
        return obj;
    }

    function minuteValue(time) {
        time = time.split(":");
        return (time[0] * 60) + (time[1] * 1);
    }


    function checkoverlapping(obj) {
        let previous = obj[0], current, overlapping = false;
        for (let i = 1; i < obj.length; i++) {
            current = obj[i]
            if (minuteValue(previous.to) > minuteValue(current.from)) {
                overlapping = true;
                break;
            }
        }
        return overlapping;
    }

</script>
Braley answered 1/6, 2018 at 2:51 Comment(0)
B
1

You can use moment to compare actual dates and check for overlaps between them:

function rangeOverlap(range1, range2, gran = "hour", inc = "[]") {

  const [ start1, end1 ] = range1;
  const [ start2, end2 ] = range2;

  // check range1 is between range2
  const startFirst = start1.isBetween(start2, end2, gran, inc)
  const endFirst = end1.isBetween(start2, end2, gran, inc)

  // check range2 is between range1
  const startLast = start2.isBetween(start1, end1, gran, inc)
  const endLast = end2.isBetween(start1, end1, gran, inc)

  return startFirst || endFirst || startLast || endLast
}

Then, consider this example:

const range1 = [
  moment("2022-02-22T10:00:00"), // start
  moment("2022-02-23T10:00:00")  // end
]

const range2 = [
  moment("2022-02-22T10:00:00"), // start
  moment("2022-02-23T10:00:00")  // end
]

const overlap = rangeOverlap(range1, range2)
console.log("Overlaps:", overlap)
Blah answered 8/11, 2022 at 16:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.