health.waiting-time
NHS England referral-to-treatment (RTT) wait in days and weekly bands, with the 18-week breach flag.
1.0.0 (not the latest) · published 2026-10-03 by charlie · Anterra
Pinned by 18 tests, run in TypeScript, Python and Rust.
Not professional advice. This capability calculates health figures from published rules. It is a software component for developers, not medical advice. Rules change and every rate here has an effective date. Check that the dates cover your case. Verify results against the official sources listed in its README, and have a clinician review how you use it, before anyone relies on the output. Provided “as is” under its licence, without warranty.
Not a medical device. It is not intended to diagnose, treat or support clinical decisions about any individual. Anyone building it into clinical software is responsible for that software’s regulatory status, and must validate it under their own clinical governance.
What it does
How long a patient has waited on an NHS England consultant-led referral-to-treatment (RTT) pathway, the way NHS England counts it: days from the clock start to the clock stop (or to the measuring date while the patient is still waiting), the weekly reporting band, and whether the 18-week standard has been breached.
Patients in England have the right to start consultant-led non-emergency treatment within a maximum of 18 weeks from referral. 18 weeks is 126 days, and a patient who has waited exactly 126 days is still within it (they are reported in the 17-18 week band); 127 days is a breach. `eighteenWeekDate` is the clock start plus 126 days, the last day on which treatment still meets the standard.
For example
rttWaitingTime(2026-01-05, —, 2026-01-05)→ days 0, completed weeks 0, week band 1, breached18 weeks false, eighteen week date 2026-05-11, clock stopped false a clock that starts on the measuring date has waited zero days, in the 0-1 week bandrttWaitingTime(2026-01-05, —, 2026-01-12)→ days 7, completed weeks 1, week band 1, breached18 weeks false, eighteen week date 2026-05-11, clock stopped false 7 days is still the 0-1 week band, which holds eight daysrttWaitingTime(2026-01-05, —, 2026-01-13)→ days 8, completed weeks 1, week band 2, breached18 weeks false, eighteen week date 2026-05-11, clock stopped false 8 days is the first day of the 1-2 week band
The function
The same function in TypeScript, Python and Rust, pinned by the same tests. Pick your language; the choice follows you around the registry.
export function rttWaitingTime(clockStart: string, clockStop: string | null, onDate: string): RttWait
| clockStart | date | the date the RTT clock started: the provider received the referral |
| clockStop | date? | the date the clock stopped (first definitive treatment or a non-treatment stop); null while waiting |
| onDate | date | the date to measure a still-waiting pathway on; never today implicitly |
| returns | RttWait |
The type it declares, generated into your project
/** The length of an RTT pathway as NHS England reports it. */
export interface RttWait {
/** clockStop (or onDate while waiting) minus clockStart */
readonly days: number;
/** whole weeks waited, days divided by 7 rounded down */
readonly completedWeeks: number;
/** n of the reporting time band ">n-1 to n weeks": 0-7 days is 1, 126 days is 18; above 104 is the ">104 weeks" band */
readonly weekBand: number;
/** more than 126 days */
readonly breached18Weeks: boolean;
/** clockStart + 126 days, the last day still within 18 weeks */
readonly eighteenWeekDate: string;
/** whether clockStop was given */
readonly clockStopped: boolean;
}
Your code names it in one line, in the file that uses it
import { rttWaitingTime } from "#fune/health.waiting-time@^1";
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { addDays, daysBetween, parseIsoDate } from "./dates_add_days.ts"; ← from dates.add-days ^1.0.0 · built alongside by fune
import { type RttWait } from "./health_waiting_time_types.ts";
/** 18 weeks: a wait of exactly 126 days is still within the standard. */
const EIGHTEEN_WEEKS_DAYS = 126;
/**
* The length of a referral-to-treatment pathway, counted from the clock start
* to the clock stop, or to onDate while the patient is still waiting. There
* are no pauses: NHS England removed them in 2015.
*/
export function rttWaitingTime(clockStart: string, clockStop: string | null, onDate: string): RttWait {
parseIsoDate(clockStart);
parseIsoDate(onDate);
if (onDate < clockStart) {
throw new RangeError(`onDate ${onDate} is before clockStart ${clockStart}`);
}
if (clockStop !== null) {
parseIsoDate(clockStop);
if (clockStop < clockStart) {
throw new RangeError(`clockStop ${clockStop} is before clockStart ${clockStart}`);
}
if (clockStop > onDate) {
throw new RangeError(`clockStop ${clockStop} is after onDate ${onDate}`);
}
}
const days = daysBetween(clockStart, clockStop ?? onDate);
return {
days,
completedWeeks: Math.floor(days / 7),
// The 0-1 week band holds eight days (0 to 7), every later band seven.
weekBand: days <= 7 ? 1 : Math.floor((days + 6) / 7),
breached18Weeks: days > EIGHTEEN_WEEKS_DAYS,
eighteenWeekDate: addDays(clockStart, EIGHTEEN_WEEKS_DAYS),
clockStopped: clockStop !== null,
};
}Install
fune build
With that line in your source, in a TypeScript project (language typescript in fune.project), fune build resolves it and its 1 dependency, pins them in fune.lock, downloads only the TypeScript package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. Or pin a range in fune.project and build in one step:
fune add health.waiting-time
The manifest, vectors and README with only the TypeScript implementation. Install it without the registry with fune add ./health.waiting-time-1.0.0-typescript.fune, or fetch it from a terminal with fune pull health.waiting-time@1.0.0:typescript.
The whole function, every language, is one file too: health.waiting-time-1.0.0.fune, 16,244 bytes, sha256 198576ddbe1a3d5b288d828d5d7ecf0d8584e072efc036b8df3c44c0abf0be82. It installs into a project of any language.
Customise it in your app
The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.
before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.
// fune: before health.waiting-time
after — your function gets the result and the arguments, and returns the final result.
// fune: after health.waiting-time
replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.
// fune: replace dates.add-days in health.waiting-time
step — your function runs at a numbered point inside the function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show health.waiting-time --steps.
// fune: step health.waiting-time after <n|label>
Tests
A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.
| Case | Arguments | Expected | |
|---|---|---|---|
| a clock that starts on the measuring date has waited zero days, in the 0-1 week band | 2026-01-05, —, 2026-01-05 | → | days 0, completed weeks 0, week band 1, breached18 weeks false, eighteen week date 2026-05-11, clock stopped false |
| 7 days is still the 0-1 week band, which holds eight days | 2026-01-05, —, 2026-01-12 | → | days 7, completed weeks 1, week band 1, breached18 weeks false, eighteen week date 2026-05-11, clock stopped false |
| 8 days is the first day of the 1-2 week band | 2026-01-05, —, 2026-01-13 | → | days 8, completed weeks 1, week band 2, breached18 weeks false, eighteen week date 2026-05-11, clock stopped false |
| exactly 18 weeks (126 days) is in the 17-18 week band and not a breach | 2026-01-05, —, 2026-05-11 | → | days 126, completed weeks 18, week band 18, breached18 weeks false, eighteen week date 2026-05-11, clock stopped false |
| 127 days breaches 18 weeks although only 18 whole weeks are completed: a naive completedWeeks > 18 check misses it | 2026-01-05, —, 2026-05-12 | → | days 127, completed weeks 18, week band 19, breached18 weeks true, eighteen week date 2026-05-11, clock stopped false |
| 125 days: 17 completed weeks, band 18 | 2026-01-05, —, 2026-05-10 | → | days 125, completed weeks 17, week band 18, breached18 weeks false, eighteen week date 2026-05-11, clock stopped false |
| 728 days is the 103-104 week band | 2026-01-05, —, 2028-01-03 | → | days 728, completed weeks 104, week band 104, breached18 weeks true, eighteen week date 2026-05-11, clock stopped false |
| 729 days is beyond 104 weeks | 2026-01-05, —, 2028-01-04 | → | days 729, completed weeks 104, week band 105, breached18 weeks true, eighteen week date 2026-05-11, clock stopped false |
| a stopped clock is measured to the stop, not to onDate | 2026-01-05, 2026-04-20, 2026-09-23 | → | days 105, completed weeks 15, week band 15, breached18 weeks false, eighteen week date 2026-05-11, clock stopped true |
| started and stopped on the same day: zero days, still a pathway | 2026-03-02, 2026-03-02, 2026-03-10 | → | days 0, completed weeks 0, week band 1, breached18 weeks false, eighteen week date 2026-07-06, clock stopped true |
Show the other 8 tests
| Case | Arguments | Expected | |
|---|---|---|---|
| stopped on the measuring date itself | 2026-01-05, 2026-05-12, 2026-05-12 | → | days 127, completed weeks 18, week band 19, breached18 weeks true, eighteen week date 2026-05-11, clock stopped true |
| the 18-week date crosses 29 February in a leap year | 2027-11-01, —, 2028-03-06 | → | days 126, completed weeks 18, week band 18, breached18 weeks false, eighteen week date 2028-03-06, clock stopped false |
| the same span in a common year is a day shorter | 2026-11-01, —, 2027-03-06 | → | days 125, completed weeks 17, week band 18, breached18 weeks false, eighteen week date 2027-03-07, clock stopped false |
| onDate before the clock start is an error | 2026-01-05, —, 2026-01-04 | → | error: is before clockStart |
| a clock stop before the start is an error | 2026-01-05, 2026-01-01, 2026-02-01 | → | error: clockStop 2026-01-01 is before clockStart |
| a clock stop after onDate is an error: the stop has not happened yet | 2026-01-05, 2026-03-01, 2026-02-01 | → | error: is after onDate |
| an impossible date is an error | 2026-02-30, —, 2026-04-01 | → | error: is not a real calendar date |
| a UK-style date is an error | 05/01/2026, —, 2026-04-01 | → | error: is not an ISO date |
More from the author
**Week bands.** RTT returns put each pathway in a weekly time band, ">n-1 to n weeks", and `weekBand` is that n. The first band, 0-1 weeks, holds eight days (0 to 7), every later band seven: 8-14 days is band 2, 120-126 days band 18, 127 days band 19. NHS England's last band is "104+ weeks", 729 days and more; `weekBand` keeps counting above 104 (729 days is 105) so a caller can still tell long waits apart, and a return should put anything above 104 in the >104 band. `completedWeeks` is simply whole weeks (days divided by 7, rounded down), for display. A clock that starts and stops on the same day is a real pathway of zero days.
**No clock pauses.** Earlier versions of the rules allowed "patient-initiated clock pauses". NHS England removed them in 2015 with the admitted pathway standard: "there is no longer any provision to report pauses or suspensions in RTT waiting time clocks ... under any circumstances". This capability therefore takes a clock start and an optional clock stop and nothing else, deliberately. Events that the rules do recognise are the caller's to apply:
- a clock stop (rules 4 and 5: first definitive treatment, a decision not to treat, active monitoring, a patient declining treatment, and so on) is the `clockStop` date; - a DNA of the first appointment nullifies the clock (rule 5e, footnote 10), and when the patient rebooks a new clock starts (rule 3e), so pass the rebooking date as a new `clockStart`; - other new clock starts (rule 3: a second bilateral procedure, a new treatment, the end of active monitoring) are likewise new pathways.
**Errors.** A measuring date before the clock start, a clock stop before the clock start, and a clock stop after the measuring date (a stop that has not happened yet) are errors. Dates are ISO `YYYY-MM-DD`, and the measuring date is always an argument, never the clock.
## Source
NHS England, "Recording and reporting referral to treatment (RTT) waiting times for consultant-led elective care", version 5.2, February 2025: section 2.2 reproduces the "Referral to treatment consultant-led waiting times rules suite" (clock starts, rules 1-3; clock stops, rules 4-5), the introduction records the removal of clock pauses, and section 10.1.7 "Measuring the length of RTT pathways" defines the time bands. https://www.england.nhs.uk/statistics/wp-content/uploads/sites/2/2025/10/Recording-and-reporting-RTT-waiting-times-guidance-v5.2-Feb25.pdf
Files
| Path | Bytes |
|---|---|
| README.md | 3,172 |
| impl/python.py | 1,529 |
| impl/rust.rs | 2,400 |
| impl/typescript.ts | 1,454 |
| vectors.json | 4,143 |