Reputation: 772
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?
Upvotes: 24
Views: 45023
Reputation: 69
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!');
}
Upvotes: -1
Reputation: 21
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.
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.
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.
Upvotes: 2
Reputation: 66334
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;
}
Upvotes: 42
Reputation: 776
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>
Upvotes: 1
Reputation: 11
//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.
Upvotes: 1
Reputation: 563
Here is refined version of what Paul posted:
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;
}
Upvotes: 16
Reputation: 51
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;
}
Upvotes: 5
Reputation: 747
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)
Upvotes: -1