'Group up date ranges by interesecting ranges
This is a variation of the gaps and islands problem. I tried finding solutions but they are all SQL based.
Problem: Given a list of date ranges, return a combined list of date ranges where none are overlapping:
Ex:
2022/01/01 - 2022/03/01
2022/02/01 - 2022/05/01
2022/07/01 - 2022/08/01
Returns:
2022/01/01 - 2022/05/01
2022/07/01 - 2022/08/01
The language doesn't really matter, just not SQL. Here is my attempt in python, I think it works but I'm not sure:
from datetime import date
from dateutil.relativedelta import relativedelta
from operator import itemgetter
date_ranges = [
{
"start": date(2022, 3, 1),
"end": date(2022, 6, 1),
},
{
"start": date(2022, 1, 1),
"end": date(2022, 4, 1),
},
{
"start": date(2022, 8, 1),
"end": date(2022, 8, 1),
}
]
def _get_agregated_dates(date_ranges):
def _is_overlapping(range1, range2):
return (range1["end"] + relativedelta(months=1)) >= range2["start"].replace(day=1)
date_ranges = sorted(date_ranges, key=itemgetter("start"))
new_date_ranges = []
range1 = date_ranges[0]
range2 = date_ranges[1]
for i in range(1, len(date_ranges)):
if _is_overlapping(range1, range2):
# Set new date range
range1["end"] = range1["end"] if range1["end"] > range2["end"] else range2["end"]
# We compared the last 2 dates, and they overlapped, so append before loop ends
if i == len(date_ranges) - 1:
new_date_ranges.append(range1)
else:
range2 = date_ranges[i+1]
else:
new_date_ranges.append(range1)
if i == len(date_ranges) - 1:
# We compared the last 2 dates, and they did't overlapped, so append before loop ends
new_date_ranges.append(range2)
else:
range1 = date_ranges[i]
range2 = date_ranges[i+1]
return new_date_ranges
print(_get_agregated_dates(date_ranges))
N.B I count consecutive months as "overlapping" on purpose
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|