Last active
June 7, 2022 22:22
-
-
Save Markcanfly/670824e41c683f455a4e9602ef583819 to your computer and use it in GitHub Desktop.
Covered Time by Intervals
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def covered_time(begin: datetime, end: datetime, ranges: List[List[datetime,datetime]]) -> timedelta: | |
"""Calculate the covered timespan of a range by other ranges | |
Takes a base range defined by begin, end, | |
and several other ranges, and calculates the amount of time covered | |
within the base range by the other ranges (overlap time) | |
Args: | |
begin: base range begin datetime | |
end: base range end datetime | |
range: [begin, end] lists of covering timestamps | |
Returns: | |
overlap: timedelta | |
""" | |
if (len(ranges) == 0): | |
return timedelta(0) | |
# Cut down each time to the base range | |
for span in ranges: | |
begin_delta = begin - span[0] | |
span[0] = span[0] + begin_delta if begin_delta > timedelta(0) else span[0] | |
end_delta = span[1] - end | |
span[1] = span[1] - end_delta if end_delta > timedelta(0) else span[1] | |
times = [] | |
for begin, end in ranges: | |
times.append({'type': 'begin', 'time': begin}) | |
times.append({'type': 'end', 'time': end}) | |
# Count covered time using a state machine | |
covered = timedelta(0) # Covered time in base range | |
previous_begin = times[0] | |
depth = 0 | |
for time in times: | |
if time['type'] == 'begin': | |
depth += 1 | |
elif time['type'] == 'end': | |
depth -= 1 | |
if depth == 1: # Entered first nested covered interval | |
previous_begin = time['time'] | |
elif depth == 0: # Exited last nested covered interval | |
covered += time['time'] - previous_begin | |
return covered |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment