Back to Feed
article 3m read

Staff scheduler only knew weeks, so I taught it single days

Dated availability and time-off exceptions now sit on top of weekly hours: an available window replaces that day's pattern, time off always wins, overnight shifts are checked per date, the same rule runs in the API and the Python solver, and a save only invalidates drafts on dates that actually changed.

Article DepthPractice

Flow

Where each check lives

  1. 1Input

    Real dates only, whole minutes, no duplicates, a cap per person.

  2. 2Rule

    Available replaces weekly hours, unavailable cuts hours out, late shifts are checked per date.

  3. 3Database

    Plain dates, sane windows, no duplicate entries, each business sees only its own rows.

  4. 4Save

    Swap the whole list at once and mark only drafts on changed dates as stale.

A weekly pattern was the one thing the staff scheduler knew about when people could work. Tuesday nine to five, Thursday noon to eight, every week. That's fine until someone has the dentist next Thursday. To say so, you had to change her weekly hours and remember to change them back. Nobody does. The pattern stops being true, and the real plan lives in the manager's head.

So I added dated exceptions. Each one is a time window on one date, laid on top of the weekly pattern. "Available" means the person can work those hours that day. "Unavailable" means they can't, which covers time off, an appointment, or a full day away.

A dated available window replaces the weekly hours

If a date has any available exception, those hours replace the weekly hours for that day. If it has none, the weekly hours apply. The shift has to fit inside that. Then any unavailable exception that overlaps the shift's hours at all means no.

In code it comes down to two steps. First check that the chosen hours cover the shift without a gap, then check that no time off overlaps it.

I'm not sure "replace" is the friendly choice. Say you work nine to five on Tuesdays and add an available window for one Tuesday from noon to eight. That day you're free noon to eight, not nine to eight. Adding hours would feel more natural, but it can't say "this day, only the morning." Replace can say both if you type your normal hours back in. Someone will get caught by it anyway.

Unavailable always wins, even against an all-day available window on the same date.

Shifts that cross midnight

A late shift that runs past midnight touches two dates, and each date can have its own rules. The check cuts the shift at midnight and tests each piece against its own date. That way Saturday's time off applies to the Saturday part of a late Friday shift.

Two copies of the rule

Both the screen where a manager assigns shifts by hand and the automatic scheduler ask "can this person work this shift?" The automatic one is a separate Python service, so the rule is written twice. I don't love that. Both sides check the data and refuse bad input instead of guessing. When a hand-made assignment fails, the error blames the dated rules if that date has any, and the weekly pattern if not. That's a hint about where to look, not proof.

The database checks too

Dates are stored as plain dates with no time zone. The database refuses impossible windows and duplicate entries, and each business can only see its own rows.

Saves mark only changed dates stale

A save replaces the person's whole list at once. It then works out which dates actually changed and marks only the draft schedules that cover those dates as out of date. A save that leaves exceptions out entirely keeps the old ones. There's a cap of about a year's worth per person, and going over is an error.

What I have is tests, plus one migration test that only reads the SQL text, not a live database. The editor does say that available windows replace the weekly hours for that date. I'm just not sure people will read it before it costs them a morning.

Keep reading

Pick up a connected idea or branch into a nearby one.

5 paths forward