Kind-of-Lost Kind-of-Lost · OR Tools · Staff Scheduler · Bus Driver Schedule · Support

Bus & Transit Driver Roster Maker

Assigns drivers to duties under rest and consecutive-day rules — and is honest about the part of transit scheduling it does not do.

Start with the limitation, because it decides whether this page is any use to you. Transit scheduling is really three problems in sequence: blocking turns a timetable into vehicle workings, run-cutting chops those workings into legal driver duties, and rostering assigns real drivers to those duties over the weeks. This tool does the third one. It does not build your duties from a timetable — if you need run-cutting, you need dedicated transit software, and no amount of configuring this will substitute for it.

If you already have your duties — an early, a middle, a late, a night, whatever your depot calls them — then rostering them is exactly what this does, and the cross-midnight handling is what makes it usable. A late duty that signs off at 01:20 and an early that signs on at 04:50 are the classic transit rest problem, and they are only three and a half hours apart across a date boundary that most scheduling templates cannot even represent.

Enter each duty as a shift with its real sign-on and sign-off times, put the number of drivers each duty needs on each day in the demand grid, and set MinRestHours to your actual minimum rest between duties. Route qualifications, depot assignment and licence categories all become skills. Spare and extraboard drivers are people with wide availability and no forced assignment — the model uses them where the roster needs them, which is what an extraboard is for.

Two things this deliberately will not do for you. It does not enforce hours-of-service rules — whether that is FMCSA in the US, EU Regulation 561/2006, or your national equivalent — because those rules are jurisdiction-specific, they change, and a scheduler that half-implements them is more dangerous than one that does not pretend. Set MinRestHours, MaxConsecutiveDays and max_hrs_week to match your regulations and treat the output as a proposal to check, not a compliance certificate. And it does not model split shifts as a single duty: a driver working a morning peak and an evening peak is two shifts on the same day, so raise max_hrs_day accordingly and watch the spread — the tightest-turnaround figure on the results page is the number to look at.

Download this sample (.xlsx)
Or drop your own workbook here — choose a file
Same sheet layout as the samples: shifts, demand all, supply all, skills, one grid per demand and per person, parameters. Download a sample first if you want the template.

Driver rostering questions

Does this do run-cutting? No. It rosters drivers onto duties you already have. Turning a timetable into duties is a different optimization problem and needs purpose-built transit software.

Can it handle split shifts? As two shifts on the same day, yes — raise that driver's max_hrs_day so both fit. What it will not do is treat the pair as one duty with a spread-time limit measured from first sign-on to last sign-off. Check the tightest turnaround on the results page and set your own limit.

Does it enforce hours-of-service law? No, and that is deliberate. Those rules differ by country and change over time. MinRestHours, MaxConsecutiveDays and the contracted-hours fields are yours to set from your own regulations.

How do I model route or depot qualifications? One demand per route group, and a skill row for each driver signed off on it. A driver without the skill cannot be assigned, whatever the cost.

What about the extraboard? Enter spare drivers as ordinary people with broad availability and no forced cells. The solver will use them where the roster needs them rather than to a fixed pattern, which is what a spare board is.

The same solver, other settings

Each of these loads a different worked example and is written for that setting, but they all run the same cross-day engine — if none of them matches yours, start from whichever is closest and replace the data.

How this differs from the other two modes

The staff scheduling optimizer on the home page works in half-hour slots inside a single day: you say how many people you need at 08:00, at 08:30, at 09:00, and it invents shift blocks to match. That is the right model when demand rises and falls through the day — a call centre, a restaurant, a shop — and the wrong model here, because every one of its rules is scoped to one day column. A 19:00–07:00 night becomes two disconnected half-shifts, and no rest rule can span the midnight boundary.

This page replaces the time axis with a shift axis. Your shifts are named blocks with real clock times, and an end time earlier than the start time simply means the shift crosses midnight. Rest between two shifts then becomes arithmetic on absolute minutes across the whole horizon rather than a special case, which is what makes cross-day rules — minimum rest, maximum consecutive days, maximum consecutive nights, no day shift after a night — expressible at all.

The third mode, the shift rotation generator, does not optimize anything: it lays out a named pattern — DuPont, Panama, Pitman, 4-on-4-off — across four crews. Use it when you want a known, published rotation and you do not need the schedule to respond to who is qualified for what, who is on holiday, or which shifts need three people instead of two.

What the solver actually decides

Coverage, skills, availability, pinned assignments and contracted hours are hard — the model physically cannot assign someone to work they are not qualified for or not available for. Coverage shortfall, minimum-hours shortfall, weekend fairness and cross-person equity are soft: each carries a penalty rather than a prohibition. That is a deliberate choice. A roster tool that answers “infeasible” tells you nothing useful; this one always returns a roster and then names the compromises it had to make, in the warnings and the unfilled-posts table.

Why the continuity numbers are on the results page

A roster can be 100% covered and still be unliveable. Everyone in a pay grade earns the same rate and coverage pins the total hours, so rearranging who works when often costs the model literally nothing — the same ward solved twice with staff listed in a different order produced 21 different shifts at an identical objective. Left alone, the solver returns whichever scattered roster it reached first. So the model carries a small penalty on each new block of consecutive days worked, and another on flipping between days and nights, and the results page reports what came out: how many blocks, how long they are, how many are lone single days, and the tightest turnaround anyone actually got. Those are the numbers to argue with, not the objective value.

Common questions

Is it free? Yes — no account, no trial. Your workbook is read to solve the model and not stored.

How many people and days can it handle? Up to 40 people and 31 days per solve. The 28-day hospital ward sample builds roughly 4,300 variables and solves in well under a minute.

What if I want a shift to be someone specific? Put f in that person's grid cell. Forced cells are hard — the solver schedules around them.

Is minimum rest really 11 hours? Only by default. 11 hours is the EU Working Time Directive figure; the US has no federal equivalent and state rules vary, so it is a parameter (MinRestHours) rather than a constant. Set it to whatever your jurisdiction or contract says.

Get an email when we ship updates to this tool. Low volume, unsubscribe anytime.