Clocks With Consequences: Treating UK Statutory Deadlines as Core Product Logic
Photo: Joe Lanman from UK, CC BY 2.0, via Wikimedia Commons
Most UK software treats a statutory deadline as a notification problem. A date is stored, a cron job wakes up, an email is sent, and everyone assumes the obligation has been handled. That approach works until a subject access request lands on the Friday before a bank holiday, a payroll submission depends on a payment date that has moved, or a Companies House filing needs evidence that the right person approved it at the right time.
Statutory deadlines are not calendar notes. They are commitments with legal consequences, and they deserve to be engineered as part of the product's domain rather than bolted on as scheduling logic.
A date is rarely just a date
UK obligations do not share a single clock. Some are expressed in calendar days, some in months, some in business days, and some in phrases such as "on or before" or "within 14 days". A subject access request has a one-month response clock, with limited scope to extend. VAT returns and payroll submissions run to their own rhythms. Companies House filings have their own periods and evidence expectations. Even where the wording looks simple, the operational meaning depends on when the clock starts, what counts as a working day and whether an extension is available.
That variation is why a generic reminder table tends to fail. It stores a date without storing the reasoning behind it. When the rules change, or when an exception is challenged, there is no way to show how the date was calculated or why a particular action was taken.
Model the obligation, not the reminder
A more durable approach is to make the statutory obligation a first-class domain object. It should capture the type of obligation, the jurisdiction, the triggering event, the clock rule applied, the calculated due date, the current status, the responsible owner and the evidence required. The calculation itself should live in a dedicated service rather than being scattered across controllers, database triggers and scheduled jobs.
Separate the trigger from the deadline. A trigger might be the receipt of a request, the end of an accounting period, a payment date or a company event. The deadline is derived from that trigger using a versioned rule. Keeping those concepts apart makes it possible to recalculate correctly when an input changes, and to explain the result to an auditor or regulator.
Store dates in the form the obligation requires. Some clocks are date-only and should not drift because a server is in another timezone. Others are instants and need Europe/London handling. Mixing the two is a common source of off-by-one errors, particularly around midnight and the clocks change.
The calendar is part of the domain
The working calendar is not an external utility that can be taken for granted. Weekends, bank holidays, devolved differences and one-off closures all affect business-day calculations. A system that hard-codes a list of English bank holidays will eventually produce the wrong date for a user in Scotland, or for a period affected by a royal mourning day or other exceptional closure.
Treat the calendar as versioned reference data. Record which calendar version was used when a due date was calculated. Make the calculation explicit and testable, rather than hiding it inside a scheduled task. Where an obligation uses calendar months, define how month-end is handled. Where it uses business days, define whether the trigger day counts. These are product decisions as much as legal ones, and they should be written down.
Evidence is part of the feature
A deadline feature is only credible if it can show what happened. Build an append-only audit trail around the obligation: when it was created, which rule version calculated the due date, what reminders were sent, who submitted what, when acknowledgements were received and what evidence was attached. If a date was manually overridden, record who changed it, why and with what approval.
This is not just for regulators. It supports internal review, handover and dispute resolution. A well-designed evidence pack can be exported for a compliance team or retained as part of the product's operational record. The alternative, reconstructing a timeline from email and memory, is expensive and unreliable.
Exceptions are the normal case
Most deadline systems are designed for the happy path and then fail at the edges. Real obligations attract extensions, late data, duplicate triggers, corrected submissions and partial acknowledgements. Model those states explicitly rather than reducing everything to "overdue". An obligation might be pending input, calculated, awaiting approval, submitted, acknowledged, extended, disputed or closed. Each state should have clear transitions and an owner.
Design for graceful degradation too. If a downstream submission service is unavailable, the product should still record the attempt, preserve the evidence and escalate. A missed integration should not erase the fact that the team acted in time.
Test the awkward cases
Deadline logic deserves the same testing rigour as pricing or permissions. Build scenario fixtures for due dates that fall on weekends, bank holidays, month-end, leap years and the clocks change. Test extensions, manual overrides and duplicate triggers. Use property-based tests where possible to check that business-day arithmetic behaves consistently across a wide range of dates.
Then rehearse operationally. Can the team find an obligation, understand its clock and produce the evidence pack under pressure? A feature that works in a unit test but cannot be operated on a busy Friday afternoon is not finished.
Build the clock into the product
Statutory deadlines are part of the product's behaviour, not an administrative afterthought. By modelling obligations as domain objects, versioning the calendar rules, preserving evidence and testing the awkward edges, UK teams can build software that does more than remind people. It can help them demonstrate that the right action was taken, at the right time, for the right reason.