Skip to content

The 24-hour reporting duty is in force. Check whether it applies to you

A Berlin user typed 09:00 and we started two different clocks

Declara4 min read
  • engineering
  • deadlines
  • timezones

We shipped a bug where the same typed time produced two different legal deadlines depending on which screen you typed it into. It is the kind of bug that is completely invisible in testing, because everything is consistent when your laptop and your server agree, and every CI runner in the world agrees with a UTC server. Here is the shape of it, and the test that would have caught it.

The short answer

An HTML datetime-local input has no timezone offset in its value. 2026-09-10T09:00 means whatever zone the code that parses it happens to be running in. Our incident form parsed it on the server, which is UTC. Our triage form parsed it in the browser, which is the user's own zone. A Berlin user typing 09:00 got 09:00Z from one screen and 07:00Z from the other — two hours apart, in opposite directions, on the field that starts the twenty-four-hour clock.Art. 14⁠(2)⁠

Wall-clock time

A date and time with no offset attached: what a clock on a wall shows, in some zone the value itself does not name. 2026-09-10T09:00 is wall-clock. 2026-09-10T09:00Z and 2026-09-10T09:00+02:00 are instants, because each of them identifies exactly one moment. A datetime-local input always produces the first kind.

Why it survives every reasonable test

The damage requires a disagreement between two parsers, and the natural way to test a form is to exercise one at a time. Each screen was internally consistent and each screen's tests passed. The asymmetry only appears when a value written by one is read back by the other, in a zone that is not UTC — which is to say, in production, in Europe, which is the only place this product is used.

It is also silent by construction. There is no exception, no malformed value, nothing in a log. A deadline appears; it is simply the wrong deadline, by an amount equal to the user's offset, and it is wrong in the direction that makes it look fine.

The test that finds it

Two assertions, and neither needs a browser.

Parse a fixed wall-clock string in at least two zones and assert the resulting instants differ by exactly the expected offset. Then parse it in a zone that observes daylight saving, on a date either side of the transition, and assert the offset changes — because a fixed +02:00 constant is the second version of this bug and it fails twice a year. Pin the test runner's TZ, or you are testing your own laptop.

If you want a single canary: take the value your form produces, round-trip it through whatever your API stores, format it back into the user's zone, and assert you got the same digits the user typed. That catches every variant of this, including the ones involving a database column that quietly dropped the zone.

The fix is at the boundary, not downstream

Everything downstream of that input was already careful. The deadline arithmetic works in UTC instants throughout and converts only for display, which makes it immune to daylight saving by construction — add twenty-four hours to an instant and you get an instant, whatever the calendar in between was doing.

None of that care helps if the instant entering it was wrong. So the rule we settled on is that a wall-clock string is converted exactly once, at the edge, in a zone the code states explicitly rather than inherits. Inside that boundary there are only instants.

Two related traps we hit on the way. Most date libraries' helpers operate in the runtime's local zone — adding a month with one of them on a server in a non-UTC zone silently shifts the deadline, so calendar arithmetic has to be written against UTC explicitly. And Intl is the thing that actually carries the zone database, which means the direction you format with and the direction you parse with can be made to agree, rather than being two independent guesses.

Why write this up

Because a compliance product is a strange thing to publish clock bugs about, and publishing them anyway is most of the argument for trusting one. The deadline is the product. If we found a two-hour error in how a deadline begins, the useful thing to do with it is describe the class of bug well enough that somebody else finds theirs.

Every deadline this product computes is on the timeline, including the one that does not run from awareness at all.

Not sure whether this applies to you?

One email a month: how many vulnerabilities were added to the CISA exploited catalogue, and how many of them sit in components that appear in real inventories. Counts only. It is not a list, and nothing else is sent.

This produces evidence, timelines and drafts. It is not legal advice, and you remain the party responsible for reporting.