I found the key to my solution in a second post and pieced it together.
There are two parts to my issue:
- How do I represent a list of dates in an effective manner
Answer: https://stackoverflow.com/a/9589929/2150673
pto = [
'2020-01-03',
'2020-01-08',
'2020-01-02',
'2020-01-07',
'2020-01-01',
'2020-01-06'
]
ordinal_dates = [datetime.datetime.strptime(i, '%Y-%m-%d').toordinal() for i in pto]
- Once you have a list of dates in integer representation, you can simply look for consecutive integers and get the upper and lower bounds of each range, and then convert back to yyyy-mm-dd format.
Answer: https://stackoverflow.com/a/48106843
def ranges(nums):
nums = sorted(set(nums))
gaps = [[s, e] for s, e in zip(nums, nums[1:]) if s+1 < e]
edges = iter(nums[:1] + sum(gaps, []) + nums[-1:])
return list(zip(edges, edges))
My complete function:
def get_date_ranges(pto_list: list) -> list:
pto_dates = [datetime.datetime.strptime(i, '%Y-%m-%d').toordinal() for i in pto_list]
nums = sorted(set(pto_dates))
gaps = [[s, e] for s, e in zip(nums, nums[1:]) if s + 1 < e]
edges = iter(nums[:1] + sum(gaps, []) + nums[-1:])
ordinal_ranges = list(zip(edges, edges))
date_bounds = []
for start, end in ordinal_ranges:
date_bounds.append((
datetime.datetime.fromordinal(start).strftime('%Y-%m-%d'),
datetime.datetime.fromordinal(end).strftime('%Y-%m-%d')
))
return date_bounds