'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