Check if more than two date ranges overlap
Asked Answered
I

8

22

I have multiple date ranges. I want to check if they are overlapping in javascript. When there are only two it is easy, I use:

if(start_times1 <= end_times2 && end_times1 >= start_times2) {}

But what is the formula when there are more than 2 date ranges?

Indre answered 1/4, 2014 at 11:44 Comment(2)
...same idea, wouldn't it be?Misguide
But how? I don't know the exact amount of dates. It can be 2 but also 3 or 4Indre
A
42

You can use nested for loops with arguments

function dateRangeOverlaps(a_start, a_end, b_start, b_end) {
    if (a_start <= b_start && b_start <= a_end) return true; // b starts in a
    if (a_start <= b_end   && b_end   <= a_end) return true; // b ends in a
    if (b_start <  a_start && a_end   <  b_end) return true; // a in b
    return false;
}
function multipleDateRangeOverlaps() {
    var i, j;
    if (arguments.length % 2 !== 0)
        throw new TypeError('Arguments length must be a multiple of 2');
    for (i = 0; i < arguments.length - 2; i += 2) {
        for (j = i + 2; j < arguments.length; j += 2) {
            if (
                dateRangeOverlaps(
                    arguments[i], arguments[i+1],
                    arguments[j], arguments[j+1]
                )
            ) return true;
        }
    }
    return false;
}
Alixaliza answered 1/4, 2014 at 11:58 Comment(6)
Because you talked about dates I put the word date in the names of these functions, but really they'd work for any Number range.Alixaliza
@PaulS. thanks for this solution, it has really saved my time today!Coorg
How do we implement this? Where is the function call that starts this off?Schaffner
how can to combine same overlapping dates?Integument
it's not a bad idea to comment your code instead of just type some code linesSidra
@Akashlal developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… --- if you're doing this in modern code, use a rest parameter instead; multipleDateRangeOverlaps(...args) { /* ... */ } and replace uses of arguments with argsAlixaliza
S
16

Here is refined version of what Paul posted:

  • Added filter and null check to allow any number of entries
  • Changed the logic so that it can be applied on an array. Eg: [{"from": value, "to": value}]
  • Adjusted overlap check to allow times having end and start as same

Script:

function dateRangeOverlaps(a_start, a_end, b_start, b_end) {
    if (a_start < b_start && b_start < a_end) return true; // b starts in a
    if (a_start < b_end   && b_end   < a_end) return true; // b ends in a
    if (b_start <  a_start && a_end   <  b_end) return true; // a in b
    return false;
}

function multipleDateRangeOverlaps(timeEntries) {
    let i = 0, j = 0;
    let timeIntervals = timeEntries.filter(entry => entry.from != null && entry.to != null && entry.from.length === 8 && entry.to.length === 8);

    if (timeIntervals != null && timeIntervals.length > 1)
    for (i = 0; i < timeIntervals.length - 1; i += 1) {
        for (j = i + 1; j < timeIntervals.length; j += 1) {
                if (
                dateRangeOverlaps(
            timeIntervals[i].from.getTime(), timeIntervals[i].to.getTime(),
            timeIntervals[j].from.getTime(), timeIntervals[j].to.getTime()
                    )
                ) return true;
            }
        }
   return false;
}
Shroud answered 22/1, 2020 at 9:31 Comment(2)
You save my dayDomineering
You might need to use <= in dateRangeOverlaps depending on your data contextInfantilism
C
5

Below code comes from my project, maybe it will help you:

function dateRangeOverlaps(startDateA, endDateA, startDateB, endDateB) {

    if ((endDateA < startDateB) || (startDateA > endDateB)) {
        return null
    }

    var obj = {};
    obj.startDate = startDateA <= startDateB ? startDateB : startDateA;
    obj.endDate = endDateA <= endDateB ? endDateA : endDateB;

    return obj;
}
Clemente answered 20/6, 2017 at 8:40 Comment(0)
S
2

Simply use the areIntervalsOverlapping function from date-fns, the "modern JavaScript date utility library".

You just have to pass the two dates as arguments to the function, and it will return true or false depending if the two dates overlaps or not.

Example

Check this example from their documentation:

areIntervalsOverlapping(
  { start: new Date(2014, 0, 10), end: new Date(2014, 0, 20) },
  { start: new Date(2014, 0, 17), end: new Date(2014, 0, 21) }
)
//=> true

This example above returned true because the two dates overlaps. Note that the 0 number (the second argument) in Date(2014, 0, 10) represents the month of January.

You can also use this areIntervalsOverlapping function to check if other time intervals (like hours in the same day) overlaps, because in JavaScript a Date object also considers hours.

Installation

If, for example, you are using Node.js (or any framework that uses it), you just have to install date-fns with

npm install date-fns --save

And then import the desired functions inside your JavaScript code like:

import { areIntervalsOverlapping } from "date-fns";

Of course date-fns is not limited to Node.js. You can use it inside any JavaScript project.

Sartre answered 23/11, 2022 at 14:11 Comment(0)
Z
1

//storing existing dates for comparison

public multipleExistingDates=[
         {startDate:'02/03/2020 05:00:00',endDate:'02/03/2020 05:30:00'},
         {startDate:02/04/2020 05:00:00'',endDate:'02/05/2020 05:00:00'},]

/The date to be compared with existing dates to check if the new date is overlapping with existing dates/

public checkOverlappingDsates(startDate:Date, endDate:Date):boolean{
  return this.multipleExistingDates.some((elem)=>{
       return( !((moment(endDate).diff(moment(elem.startDate))) < 0 || 
              (moment(startDate).diff(moment(elem.endDate))) > 0;})

Note: If the date is overlapping, the function return true else false. Also , you would need to install moment for date comparison.

Zelda answered 9/4, 2020 at 10:1 Comment(0)
A
1

Why don't we use moment and moment-range, is it not supported across all browsers? 🤔

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

const events1 = [{
    "Date": "05/15/2021",
    "EndTime": "17:00",
    "StartTime": "16:00"
},
{
    "Date": "05/15/2021",
    "EndTime": "18:00",
    "StartTime": "17:00"
},
{
    "Date": "05/15/2021",
    "EndTime": "18:45",
    "StartTime": "17:45"
}
];

const events2 = [{
    "Date": "05/15/2021",
    "EndTime": "17:00",
    "StartTime": "16:00"
},
{
    "Date": "05/15/2021",
    "EndTime": "18:00",
    "StartTime": "17:00"
},
{
    "Date": "05/15/2021",
    "EndTime": "19:45",
    "StartTime": "18:45"
}
];

function checkOverlap(timeSegments) {

    var overlap = timeSegments
        .map(r =>
            timeSegments.filter(q => q != r).map(q =>
                moment.range(
                    moment(q.Date + " " + q.StartTime),
                    moment(q.Date + " " + q.EndTime)
                ).overlaps(
                    moment.range(
                        moment(r.Date + " " + r.StartTime),
                        moment(r.Date + " " + r.EndTime)
                    )
                )
            )
        );

    console.log(overlap.map(x => x.includes(true)).includes(true));
}

checkOverlap(events1);
checkOverlap(events2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-range/4.0.2/moment-range.js"></script>
Almonte answered 15/5, 2021 at 10:1 Comment(1)
One could even use its successor luxon with the built-in Interval type.Indiction
D
-1

Wouldn't be too hard to do recursively. Make a method overlap which returns the overlapping daterange for two dates. Then in your hasOverlap(list dates) method, if the list is two items, it's simple, else, return hasoverlap(overlap(dates[0], dates[1]), rest of list)

Dunning answered 1/4, 2014 at 11:55 Comment(1)
A range is always 2D, a list is 1D but can have unknown length, You have enough knowns to do this without recursionAlixaliza
I
-1

No matter the language, the basic logic to see if two date ranges overlap is:

max(range_1_start, range_2_start) <= min(range_1_end, range_2_end)

In JavaScript syntax, that might look like this:

function doDatesOverlap(start_1,end_1,start_2,end_2){
    return Math.max(start_1,start_2) <= Math.min(end_1,end_2);
}

var start_1 = new Date('01/01/2023');
var end_1 = new Date('01/31/2023');
var start_2 = new Date('01/15/2023');
var end_2 = new Date('02/15/2023');

if(doDatesOverlap(start_1,end_1,start_2,end_2)){
    console.log('They overlap!');
}
Intendance answered 11/2, 2023 at 2:20 Comment(1)
The question is about more than two date ranges overlapping.Indre

© 2022 - 2024 — McMap. All rights reserved.