Exercise 1 solution from datetime import datetime, timedelta def at(h, m=0): return datetime(2026, 11, 2, h, m) def merge(intervals): out = [] for s, e in sorted(intervals): if out and s <= out[-1][1]: out[-1] = (out[-1][0], max(out[-1][1], e)) else: out.append((s, e)) return out meetings = [(at(14), at(15)), (at(9), at(10, 30)), (at(10), at(11)), (at(11), at(11, 30)), (at(9, 15), at(9, 45)), (at(16), at(16, 30))] merged = merge(meetings) total = timedelta() for s, e in merged: print(s.strftime("%H:%M"), "-", e.strftime("%H:%M"), e - s) total += e - s print("Total booked:", total) print("Sum of raw lengths:", sum((e - s for s, e in meetings), timedelta())) Output (run, and exactly as shown): 09:00 - 11:30 2:30:00 14:00 - 15:00 1:00:00 16:00 - 16:30 0:30:00 Total booked: 4:00:00 Sum of raw lengths: 5:00:00 Explanation: the 09:15-09:45 meeting sits inside 09:00-10:30, and 10:00-11:00 overlaps it, so the first block runs 09:00 to 11:30 (11:00-11:30 touches the end, and the merge treats touching as joined). That block is 2:30, not the raw sum of its parts (1:30 + 1:00 + 0:30 + 0:30 = 3:30). Total booked is 4:00; raw lengths add up to 5:00 because overlapping time is counted twice. Rule: merge first, then sum. The max() of the ends is what stops a long meeting being cut short by a shorter one that follows it.