Calendars: the thing that turns a duration into a date
A calendar states which days and hours are worked. Every duration in a schedule is a count of working time, every date is a position, and the calendar is the only thing that converts between them — so "five days" is not a fixed quantity and two activities of identical duration on different calendars finish on different days.
This page is about what calendars do to a schedule: which quantity is
counted on which calendar, how activity, project and resource calendars differ,
what a lag is counted on, and what happens when a calendar changes between
updates. How a calendar is encoded in a P6 export is a separate subject, and
inside clndr_data owns it.
Working days and calendar days are different currencies
A contract states durations in calendar days as often as in working days. A schedule states them in working days almost always. Mixing the two is the cheapest way to produce a wrong number that looks right.
Three rules follow, and the third gets broken quietly. A duration is a count, not a span: ten working days occupies fourteen calendar days on a Monday-to-Friday week and eleven on a six-day week, the count unchanged and the finish date moved. A date difference is a span, not a count: converting elapsed days back to working days needs a calendar. And counts taken on different calendars must not be added — on a network using several, which is most real networks, "three days here plus four days there" is not seven of anything. When this project reports a finish movement in working days it names the calendar the count was taken on, because on a mixed network the choice is arbitrary and it changes the number.
Shifts, hours per day, and the divisor
A calendar states shifts — clock times on each working day. It also, separately, states an hours-per-day figure, and the two can disagree.
That is not a corruption. The hours-per-day figure is the divisor every duration in the file converts through: P6 stores durations in hours, and the duration in days is the hours divided by that figure. The shifts describe when work happens. A file can declare eight hours a day while its shifts describe ten.
Three things follow that a reviewer can check. A day may carry several shifts and the gap between them is unpaid — 08:00–12:00 plus 13:00–17:00 is an eight-hour day, not a nine-hour one, and ignoring the gap drifts every intra-day timestamp by the length of the lunch break. A shift finishing at or before its start is overnight, not zero-length. And when the declared figure and the shifts disagree, the direction matters: this project reports it by name either way, uses the shifts where they run longer than the declared day because the stored dates in such files are consistent with them, and keeps the declared figure where they read shorter, because every way of misreading a week biases the shift figure low and never high.
Fractional durations
A duration that is not a whole number of working days has to go somewhere. This project rounds up: an activity needing 33 hours on an eight-hour calendar occupies five days, because you cannot schedule a crew for a fraction of a shift and then hand the space over. It is stated here because it is otherwise invisible to anyone reading a report. The obvious alternative — adding a day to every fractional duration, as a heuristic to recover what a whole-day axis loses — was built and measured here, made agreement with P6 substantially worse, and was refused on that measurement. See what this does not do and is this real?.
Exceptions: a shutdown and a make-up day are the same field
A calendar's exceptions are dated departures from its weekly pattern, and the only thing separating the two kinds is whether the exception carries shifts:
| Exception | Meaning |
|---|---|
| Carries at least one shift | A working exception — a make-up Saturday, or a day worked short |
| Carries no shift at all | A shutdown — a holiday, or one day of a Christmas closure |
Both are exception records, and a reader that looks in the wrong place turns
every make-up day into a shutdown — silently, and in the direction that makes the
schedule look later than the contractor planned it. That failure and seven
others are in inside clndr_data.
What matters at the scheduling level is that exceptions have no downstream symptom. Lose a two-week December shutdown and every date, every float value and every delay attribution moves together; the schedule still reads as entirely reasonable, and nothing in the output points at the calendar. That is why a calendar inventory is the first thing to ask for and the last thing anybody does.
Activity, project and resource calendars
A P6 export records a calendar's kind, and the three kinds do different jobs.
| Kind | What it governs | Where it comes from |
|---|---|---|
| Global | Shared working weeks and shutdowns, inherited by project calendars | The calendar table, flagged as global |
| Project | The project's own working pattern, including its default for activities that name none | Derived from a global calendar and storing only its own departures |
| Resource | When a named crew or item of plant is available, independently of the activity's calendar | The resource table's own calendar reference |
Three consequences. Every activity names its own calendar and the project's default is a fallback — an activity naming no calendar, or naming one the file does not contain, falls back to it, and this project reports the second case by name, because an activity silently rehomed onto a different working week is a date change with no visible cause. A project calendar stores departures, not the whole pattern: the shared shutdown calendar can live entirely in the parent record, so reading only the child's own definition works days the project does not; the parent link is a field P6 stored rather than a figure it computed, so following it is a decoding step and not a borrowed answer, and the chain can be several deep. And a resource calendar can change a levelling answer without touching the network — a crew on a Monday-to-Friday calendar is not available on a Saturday even when the activity's calendar works it, so the logic and the critical path are unchanged while the resource-feasible answer moves.
Which quantity is counted on which calendar
Almost every "why does this number disagree" question resolves to a row here.
| Quantity | Counted on |
|---|---|
| An activity's duration | That activity's own calendar |
| An activity's total float and free float | That activity's own calendar |
| A relationship's lag | Whichever calendar the project's lag calendar setting names — predecessor, successor, project default, or elapsed time |
| A constraint date | Resolved to a boundary on the constrained activity's calendar |
| The project start and finish | Instants, not counts; a date, not a number of days |
| A reported finish movement | A calendar that has to be named, because on a mixed network the choice is arbitrary |
The lag row is the one that surprises people, because the governing calendar is a project-level setting rather than a property of the relationship: change the setting and every lagged link in the file changes meaning with no edit to a single link. Lags and leads works that through, with a worked example where one start-to-start lag lands on a Friday counted one way and the following Monday counted the other.
When a calendar changes between updates
Changing a calendar between two updates expands or contracts the apparent project duration with no logic change, no duration change, and no work moving. Add a shutdown week and the forecast finish slips a week. Make a past non-working day working and it pulls in.
The awkward part is that the legitimate and illegitimate versions are the same edit. Recording a granted weather day by making a past working day non-working is ordinary, correct practice. Absorbing a slip by quietly adding holidays reaches forward past the status date and moves a forecast. In the exported file those two look identical: a changed exception record on a named calendar.
Published update-review practice — AACE RP 53R-06 is the document, and its method rather than its wording is described here — asks that each calendar change be documented, and treats a change reaching forward past the status date differently from one confined to the past. That test is a judgment about intent, so this project's rule names the changes and leaves the determination to the reviewer: which calendars were added, which removed, and which altered in pattern or hours since the prior version. It does not conclude that a change was improper, nor that an undocumented one was innocent.
A related trap: two updates whose activities have moved between calendars is not the same case as two updates whose calendars have changed. Both move dates, and only the second shows up in a calendar inventory.
NYSDOT names calendars expressly among the ways a schedule can appear to share total float while not doing so: a restrictive enough calendar absorbs time that would otherwise show as float. The position who owns the float takes, and this page does not duplicate, is that a calendar reflecting a genuine seasonal restriction and one written to absorb float are the same object in the export — so an inventory is evidence and not a finding, because the distinction is intent.
What the specifications say about calendars
Less than they say about constraints and lags, and mostly about disclosure and default settings.
| Document | The requirement, in shape | Where |
|---|---|---|
| SCDOT | Time periods fixed at 8 hours a day and 2,000 a year, among a list of required default settings | Default Values |
| NYSDOT | Over-restrictive calendars named as a float-suppression mechanism | Item 639 |
| WisDOT | Calendar properties checked as part of the agency's own review filters | §108.4.4.3 and the review guidance |
| MnDOT | Calendars among the network content the narrative must account for | §1803.3C.1 |
Where a specification fixes hours per day, note what that binds: the divisor every duration converts through — not necessarily the shifts, which can still describe something else. The two disagreeing is a reportable state, not an error to be silently resolved.
What a calendar inventory shows
The thing to ask for before arguing about a date. Every calendar, with its name, kind, working week, declared hours per day and the hours its shifts actually describe. Every exception, dated and classified as a shutdown or a working exception. Which activities use each calendar — one nobody uses is not a finding and one carrying the whole driving chain is. What changed since the prior update. And which calendars were read completely, with each failure named: an empty definition, an unreadable one, a week with fewer than seven days parsed, a calendar on which nobody ever works. Those are reported by name rather than absorbed into a default week, because a default week is the failure mode that produces a plausible schedule finishing early.
What this tool does, and what it refuses
It reads each calendar's weekly pattern, shift times and dated exceptions, follows the parent-calendar chain, and states what it found — including where a calendar's declared hours disagree with its own shifts, and where a calendar could not be read at all. It computes every duration, float value and lag on the calendar that governs it, names that calendar beside any day count it reports, and identifies calendar changes between two versions.
It discloses what it cannot see. The work pattern here is day-granular, so a six-hour Saturday is worked as a whole day and the overstatement is stated in the output rather than corrected in silence.
It refuses to decide whether a calendar is over-restrictive, whether a calendar change was proper, or whether a shutdown is excusable. Those are determinations for the reviewing authority.
Related reading
- Inside
clndr_data— how a P6 calendar is encoded, and eight ways two readers disagree about one file. - Lags and leads — the calendar that governs a lag, and why it is a setting.
- Total float and free float — why a float figure needs its calendar named.
- P6 scheduling options — the settings a file records.
- What this does not do — the day-granular work pattern and what it costs.
Source: web/pages/schedule-calendars.md. Source commit date: 2026-09-11.