Kind-of-Lost Kind-of-Lost · OR Tools · Staff Scheduler · 3-Shift Schedule · Support

3-Shift Schedule Generator

Three eight-hour shifts, continuous line, weeks at a time — with the 22:00 hand-off treated as one shift instead of two half-days.

A continuous line on three eight-hour shifts is the oldest 24/7 scheduling problem there is, and it has a specific character that healthcare rostering does not: the people are largely interchangeable, the headcount per shift is the whole requirement, and the thing you are really optimizing is how the crew loading falls across the week — four operators on the line Monday to Friday, two at weekends, every shift, every day, without anyone working nights for a fortnight straight.

The sample here is 14 days, 18 operators, one qualification, and shifts at 06:00–14:00, 14:00–22:00 and 22:00–06:00. That last one is the reason this page exists: the C shift starts on one calendar day and ends on the next, and a scheduler that thinks in days will either refuse it or quietly split it into a 22:00–24:00 stub and an 00:00–06:00 stub, at which point the rest rule that is supposed to protect the operator has nothing to attach to.

Two parameters matter more here than anywhere else on the site. MaxConsecutiveNights caps the C-shift run — the sample uses four, which is on the tolerant side for a manufacturing setting and worth arguing about with whoever owns your fatigue policy. And BlockStartPenalty is what stops the solver returning a technically valid roster where an operator works Monday, is off Tuesday, works Wednesday, is off Thursday. Rearranging who works when usually costs the model nothing at all, since everybody is on the same rate, so without that penalty it returns whichever scattered pattern it happened to reach first. With it, on this sample, lone single days worked drop from 31 to 16 with coverage unchanged.

If what you actually want is a named crew pattern rather than an optimized assignment — four crews of twelves, everyone on the same repeating cycle — the rotation generator is the faster route. It gives you DuPont, Panama and the rest with no data entry at all. Use this page instead when headcount varies by day or by shift, or when not everyone can run every station.

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.

Continuous-operation scheduling questions

Can I have different headcount per shift and per day? Yes — that is the point of the demand grid. Every cell is a shift × day pair, so weekends can run two on the line and weekdays four, or nights can be lighter than days, without any special configuration.

Eight-hour or twelve-hour shifts? Either. Shift lengths come from the clock times you enter, not from a setting. Three eights and two twelves are both just rows in the shifts sheet, and you can mix lengths in one schedule.

What about swing shifts and rotating crews? This page assigns individuals, so a crew rotation emerges from the constraints rather than being imposed. If you want the rotation itself imposed — the same four crews cycling through a published pattern — generate it on the rotation pages instead.

How do I model different qualifications per station? Make each station a separate demand and list which operators are qualified for it in the skills sheet. An operator with no skill row for a demand cannot be assigned to it — that is structural in the model, not a penalty.

Does it account for shift differentials? Yes. NightDifferential and WeekendDifferential multiply the hourly cost for those shifts, so the solver prefers cheaper cover where the rules allow it.

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.