Lag and lead: the unit, the calendar, and why the same number means two things
A lag is a delay applied to a relationship rather than to an activity: the successor's bound is advanced by the stated amount. A lead is a negative lag, permitting a successor to begin before its predecessor's driving event. Those definitions are in the glossary, and they are where most treatments of the subject stop — and they are not sufficient to compute a date. A lag in a real file carries five independent things, each of which two tools can read differently, and only one of them is the number printed in the relationship column.
| What a lag carries | Where it comes from | What goes wrong |
|---|---|---|
| Relation type | The link's own type — FS, SS, FF, SF | Decides which end of the predecessor the lag runs from and which end of the successor it bounds |
| Sign | The stored value | A lead is not a small lag; the sign has to survive every conversion |
| Magnitude | The stored value | Off by one working day is invisible on a seven-day calendar |
| Unit | Hours in a P6 export, converted to the working-day axis | The divisor is a choice, and it is per calendar |
| Governing calendar | A project-level scheduling setting, not a property of the link | The same link with the same lag means different elapsed time in two files |
The last two are the ones nobody documents, so this page spends most of its length there.
The unit: a lag is stored in hours and read through a divisor
In a P6 XER export the relationship table stores lag as lag_hr_cnt — a count
of hours, not days. Turning it into a duration on a working-day axis
requires dividing by an hours-per-day figure, and that figure is a property of a
calendar, so the answer depends on which calendar supplies it.
Consider one file with two calendars, one declaring eight hours a day and one declaring ten. A stored lag of sixteen hours is two days on the first and 1.6 on the second. This project rounds duration conversions up — a lag that does not fill a whole working day still occupies one, because you cannot hand a crew a fraction of a shift and then hand the space to somebody else — so the 1.6 becomes two as well, and a twelve-hour lag becomes two on both. The rounding is deliberate and is stated here because it is otherwise invisible.
This project divides by the successor's hours-per-day. That is a choice. A gross error in the divisor demonstrably moves answers away from P6's stored dates, so the divisor is being read and applied; it has not been established that P6 uses the successor's figure rather than the predecessor's. On a whole-day axis the choice rarely changes a date, which is exactly why an error in it would be hard to see. The open question is recorded rather than resolved — see what this does not do. A lag expressed in days in any report is therefore a derived figure: the file said hours, so ask what divided it.
The governing calendar is a setting, not a property of the link
This is the part that makes two tools disagree about one file while both are reading it correctly.
A lag is a span of time, and a span of time has to be counted on a calendar. P6
stores the choice as a project-level scheduling option — sched_calendar_on_relationship_lag
in an XER export — with four values:
| Setting | What the lag is counted on |
|---|---|
| Predecessor Activity Calendar | The predecessor's working week and holidays |
| Successor Activity Calendar | The successor's |
| 24-Hour Calendar | Elapsed time: every day counts, worked or not |
| Project Default Calendar | The project's nominated default |
Nothing about the relationship records which one applies. Change the project setting and every lagged link in the file changes meaning, with no edit to a single relationship.
Read as sentences, from a hand-computed table used to check this project's arithmetic. Take a data date of Monday 6 January 2025 and a predecessor with no predecessor of its own, so it starts that Monday. Give it a start-to-start link with a lag of four days, and put the two activities on different working weeks — the predecessor Monday to Thursday, the successor Monday to Friday. Counted on the predecessor's calendar, four working days runs Monday, Tuesday, Wednesday, Thursday, so the successor starts Monday 13 January. Counted on the successor's, the same four days land on Friday 10 January. One link, one lag, two answers a working day apart, decided by a checkbox nobody looks at.
The elapsed-time setting is starker. A finish-to-start lag of three days behind a predecessor finishing Friday 10 January releases its successor on Thursday 16 January in working days on a Monday-to-Friday week, and on Tuesday 14 January as elapsed days, because the weekend counts.
Do not reason about this from taste. Of the four modes only one appears in the exports read for this project with any link the setting could change — and one mode that a sibling scheduling engine treats as natural reproduced P6 on none of the cross-calendar start-to-start links available to score it. The other three remain unscored against P6 here, and this project does not present unscored modes as agreement. VDOT names the setting outright, requiring the Predecessor Activity Calendar at II.2.A(13)(g) — a specification writer noticing exactly this problem. See P6 scheduling options.
Two spaces, and the two conversions that cross
The subtlest thing about a lag is not the number: it is where the number lands.
A start instant means work resumes at the beginning of a day. A finish boundary means work ended at the close of the day before. Between the close of the last worked day and the start of the next, no work happens — so those are one moment with two spellings, and the map between them is exact both ways. It is also the identity whenever the intervening run is empty, which is every day of a seven-day calendar and most days of any other. That is why getting it wrong is nearly invisible.
Each relation type runs its lag from one end of the predecessor and consumes the result at one end of the successor:
| Type | The lag is stepped from | The result bounds | Conversion needed |
|---|---|---|---|
| Finish-to-start | The predecessor's finish | The successor's start | Boundary to start |
| Start-to-start | The predecessor's start | The successor's start | None |
| Finish-to-finish | The predecessor's finish | The successor's finish | None |
| Start-to-finish | The predecessor's start | The successor's finish | Start to boundary |
Finish-to-start's crossing is made by the forward pass itself, which every engine has to do. Start-to-finish's crossing was made by nobody in this project's scheduler until it was found and fixed: the lag was stepped in start space and consumed as a boundary with no conversion, which gains a working day whenever the day before the bound is not worked.
The witness shows how the error hides. On a calendar where Friday is not worked, a start-to-finish lag advanced to the day start of a Saturday. Converted, that is the boundary at the close of Thursday. Read without conversion, a snap forward pushed the non-worked Friday up and returned the close of the Saturday — two days later. P6's stored answer and an independent third-party scheduling library both gave the Thursday. On a calendar with no gap both readings agree, which is why the defect survived every test until a file with a Friday off arrived.
The correction is a conversion and not a subtraction. A neighbouring link in the same file advanced to a day whose preceding day was worked, so the boundary was already canonical and the conversion was a no-op; subtracting a day there would have been wrong. If you are auditing a scheduler, that is the control case to ask for.
Start-to-finish is the rarest of the four and the hardest to justify: it says the successor may finish once the predecessor starts, and it is the only type whose lag crosses both boundaries at once. UFGS §3.3.16(b) prohibits it outright, VDOT prohibits it by omission, and DCMA-EA PAM 200.1 §4.4 states it should be used very rarely and with detailed justification. It is also rare in the wild — across the relationships read for this project, a fraction of one percent, concentrated in a handful of files. Which is why a scheduler can carry a start-to-finish defect for a long time unnoticed.
Leads, and why the prohibitions are near-universal
A negative lag pulls a successor's bound earlier than the predecessor's driving event. The reason given for prohibiting it is consistent: a lead models an overlap the logic should state directly, usually by splitting the predecessor and tying the halves. The prohibitions, in the shapes the documents take:
| Document | The rule, in shape | Where |
|---|---|---|
| UFGS | "Leads (negative lags) are prohibited", alongside a requirement that lags be reasonable and not used to replace proper schedule logic | §3.3.16(a) |
| DCMA-EA PAM 200.1 | Leads counted as a metric with a goal of zero; lags counted separately with a threshold of 5 percent of links | §4.2, §4.3 |
| NYSDOT | Lag may not exceed 10 days; negative lag prohibited | Item 639 F.1(i) |
| MDOT SHA | Negative lag not used | — |
| SCDOT | Negative lag not used; lag minimised in favour of an activity standing for it | Default Values |
| WisDOT | All relationships finish-to-start, with no leads and no lags | §108.4.4.3 |
| MnDOT | Lags and leads need the Engineer's agreement in advance, and may be required to be replaced by an activity | §1803.3B.2, §1803.3A.4 |
| VDOT | Lag prohibited unless the Engineer permits it | II.2.A(9)(e) |
The substantive complaint behind all of them is the same: a lag is time nobody is accountable for. It has no owner, no resource, no progress to record against it and no way to be reported late; an activity standing in its place has all four. That is an argument the specifications make and this project does not extend.
One mechanical note follows from the unit section above: the sign has to survive the hours-to-days conversion. A routine taking an absolute value, or rounding a negative the way it rounds a positive, turns a lead into a lag or shortens it by a day.
Two smaller points change what a report means. A stated zero lag and no lag at all mean the same thing to the arithmetic and different things to a reviewer, and the distinction can be erased on import. And on progressed work part of a lag has already elapsed: both passes, the free-float calculation and any as-late-as-possible placement must receive the same remaining figure, or the dates and the float disagree with each other.
What a lag inventory shows
Per file: how many links carry a lag and how many a lead, as counts and shares, which is what the DCMA metrics count; the distribution of magnitudes, since a lag of hundreds of days is usually a units mistake; the split by relation type; the unit as the file states it, beside the converted figure; and the declared governing calendar.
The useful last line is how many lagged links actually cross a calendar boundary, because those are the only links on which the calendar setting changes an answer. An unusual lag calendar with no cross-calendar lagged links has declared something that does not matter; the same declaration over hundreds of them is the first thing to check when two tools disagree about the file.
What this tool does, and what it refuses
It reports relationship types and lags as the imported file states them, with the unit the file used and the converted figure beside it, and reads the file's own scheduling options rather than substituting defaults.
It states which of its lag behaviours are checked against P6's stored answers and which are not: three of the four lag-calendar modes have no scorable evidence in the files available here, and presenting them as agreement would be a claim nobody measured. See is this real?.
It refuses to decide whether a lag is reasonable, justified, or a substitute for logic that should have been stated. The reviewing authority determines that.
Related reading
- Calendars — the calendar a lag is counted on, and what else it governs.
- P6 scheduling options — the settings a file records and what each one changes.
- Total float and free float — a lag already consumed leaves no free float, which is where a lag error surfaces.
- The DCMA 14-point metrics — §4.2, §4.3 and §4.4 in the source's own words.
- What an XER file is — where the relationship table sits.
Source: web/pages/lags-and-leads.md. Source commit date: 2026-09-11.