Question: I'm looking for a data type to help me model resource availability over fluid time.  We're open from 9 til 6 and can handle 5 parallel jobs. In my imaginary programming land, I've just initialised an object with that range with a value of 3 across the board. We have appointments on the books, each with start and end times. I need to punch each of those out of the day That leaves me with a graph of sorts where the availability goes up and down, but ultimately allowing me to quickly find time ranges where there is remaining availability.  I've come at this problem from many directions but always come back to the fundamental problem of not knowing a data type to model something as simple as an integer over time. I could convert my appointments into time series events (eg appointment arrives means -1 availability, appointment leaves means +1) but I still don't know how to manipulate that data so that I can distil out periods where the availability is greater than zero.  Somebody's left a close-vote citing lack of focus, but my goal here seems pretty singular so I'll try to explain the problem graphically. I'm trying to infer the periods of time where the number of active jobs falls below a given capacity.  Turning a range of known parallel capacity (eg 3 between 9-6) and a list of jobs with variable start/ends, into a list of time ranges of available time.

Answer: My approach would be to build the time series, but include the availability object with a value set to the availability in that period. availability: [ { "start": 09:00, "end": 12:00, "value": 4 }, { "start": 12:00, "end": 13:00, "value": 3 } ]  data: [ { "start": 10:00, "end": 10:30, } ]  Build the time series indexing on start/end times, with the value as the value. A start time for availability is +value, end time -value. While for an event, it'd be -1 or +1 as you said. "09:00" 4 "10:00" -1 "10:30" 1 "12:00" -4 "12:00" 3 "13:00" -3  Then group by index, sum and cumulative sum. getting: "09:00" 4 "10:00" 3 "10:30" 4 "12:00" 3 "13:00" 0  Example code in pandas: import numpy as np import pandas as pd data = [ { "start": "10:00", "end": "10:30", } ] breakpoints = [ { "start": "00:00", "end": "09:00", "value": 0 }, { "start": "09:00", "end": "12:00", "value": 4 }, { "start": "12:00", "end": "12:30", "value": 4 }, { "start": "12:30", "end": "13:00", "value": 3 }, { "start": "13:00", "end": "00:00", "value": 0 } ] df = pd.DataFrame(data, columns=['start', 'end']) print(df.head(5)) starts = pd.DataFrame(data, columns=['start']) starts["value"] = -1 starts = starts.set_index("start") ends = pd.DataFrame(data, columns=['end']) ends["value"] = 1 ends = ends.set_index("end") breakpointsStarts = pd.DataFrame(breakpoints, columns=['start', 'value']).set_index("start") breakpointsEnds = pd.DataFrame(breakpoints, columns=['end', 'value']) breakpointsEnds["value"] = breakpointsEnds["value"].transform(lambda x: -x) breakpointsEnds = breakpointsEnds.set_index("end") countsDf = pd.concat([starts, ends, breakpointsEnds, breakpointsStarts]).sort_index() countsDf = countsDf.groupby(countsDf.index).sum().cumsum() print(countsDf) # Periods that are available df = countsDf df["available"] = df["value"] > 0 # Indexes where the value of available changes # Alternatively swap out available for the value. time_changes = df["available"].diff()[df["available"].diff() != 0].index.values newDf = pd.DataFrame(time_changes, columns= ["start"]) # Setting the end column to the value of the next start newDf['end'] = newDf.transform(np.roll, shift=-1) print(newDf) # Join this back in to get the actual value of available mergedDf = newDf.merge(df, left_on="start", right_index=True) print(mergedDf)  returning at the end:   start end value available 0 00:00 09:00 0 False 1 09:00 13:00 4 True 2 13:00 00:00 0 False