Rescheduling Events

“Just cancel the old ones and book new ones.”

Here are some challenges I faced.

I recently built a rescheduling engine for multi-part bookings (like consult + treatment) with constraints like:

  • user availability
  • event durations
  • time conflicts
  • step order (e.g., numbing must come before injection)

Problem 1: Greedy Scheduling Fails Fast #

At first, I reached for a simple greedy strategy:

sorted_slots = sorted(slots)
selected = sorted_slots[:3]

It worked for one event. But chaining two?

Step 1: 10:00–10:30
Step 2: 10:15–10:45  ← Overlaps!

Sometimes step 2 came before step 1. Other times, an “available” slot wasn’t actually bookable due to stale data.

Fix: Use a Sliding Window Matcher #

def find_valid_chains(slots_list, durations):
    chains = []
    for i in range(len(slots_list[0])):
        chain = [slots_list[0][i]]
        valid = True
        for j in range(1, len(slots_list)):
            next_slot = next((
                s for s in slots_list[j]
                if s >= chain[-1] + timedelta(minutes=durations[j-1])
            ), None)
            if not next_slot:
                valid = False
                break
            chain.append(next_slot)
        if valid:
            chains.append(chain)
    return chains

Now, all steps occur in the right order without overlaps.


Problem 2: Time Zones Break Everything #

One day, all the times looked correct. The next? Off by 8 hours.

Turns out the API gave me UTC timestamps, but my app logic compared them to local time (like 10:00am in GMT+8).

Fix: Normalize All Timezones #

from datetime import timezone, timedelta

slot_dt = datetime.fromisoformat(slot.replace("Z", "+00:00"))
local_dt = slot_dt.astimezone(timezone(timedelta(hours=8)))

Lesson: never compare datetime strings directly. Always use timezone-aware datetime.


Problem 3: Updating Isn’t Always Allowed #

I assumed I could reschedule by modifying the original event. Sometimes, the API silently failed or returned errors for:

  • locked events
  • past events
  • already modified records

What I Had to Do Instead #

If update fails:

try:
    update_event()
except HttpError as e:
    cancel_old()
    create_new()

Yep, sometimes rescheduling means cancel and recreate.


Comparing Algorithms #

StrategyOutcome
GreedyFast but fails with multiple steps
Backtracking + ConstraintsWorks but slow, too many combinations
Sliding WindowFast, respects order, easy to debug

Sliding Window gave the best tradeoff between correctness and speed.


Bonus: Graph-Based Scheduling #

I experimented with modeling slots as a graph:

  • Each node = a time slot
  • Edge = valid time gap between steps

This enabled basic pathfinding with BFS:

paths = bfs(start_slot, goal_condition)

It’s overkill for most cases, but cool when scheduling across multiple days or optimizing for least wait time.


Final Thoughts #

What I learned building this:

  • APIs are messy. Slots might be stale, out-of-sync, or conflict-prone.
  • Timezones can be an oversight.
  • Harder than I thought!