Formatting and locale / Dates and times
Why 03/04/2026 is a defect in a document that crosses a border
An all-numeric date whose day and month can be swapped without producing anything that looks wrong, which makes it unreadable rather than merely unclear.
The defect
03/04/2026 is the third of April or the fourth of March, and both are valid dates, so nothing about the string signals that there is a question. That is what makes it worse than an obviously malformed value: a malformed date gets queried and an ambiguous one gets acted on. On a document with a due date, a delivery date or an expiry, the two readings are a month apart. The ambiguity only disappears when the day is above twelve, which means a system can run for years producing dates that happen to be unambiguous and then produce one that is not.
What it does to the document
A written month is wider than a numeric one and varies in width between months and between languages, so a date column sized for the numeric form clips or wraps once the word goes in. Size the column for the longest month name in every language the document is issued in, and set the date to not wrap.
The decisions
Reasons rather than a description of the code. Formatting rules are data that changes, so most of these are about taking the rule from a maintained source rather than encoding today's answer.
- Write the month as a word or an abbreviation in anything a person reads. Three extra characters removes the entire class of error.
- Use the ISO ordering, year then month then day, where a numeric date is unavoidable, because it is unambiguous and sorts correctly as text.
- Never use a bare two-digit year. It reintroduces an ambiguity of a century for no saving worth having.
- Keep one date format across the whole document. A document with two formats teaches the reader neither.
- Format from a date type, not by concatenating fields, so the ordering comes from the locale rather than from the order the fields happened to be in.
- Where the document is a legal or financial instrument, prefer the fully written form for the dates that matter, however verbose, and keep numeric forms for tables where space is genuinely tight.
In code
The formatting happens before the markup exists, so this is mostly code rather than CSS. The wrong version is kept in a comment where the wrong version is the thing people write.
const due = new Date(Date.UTC(2026, 3, 13)); // 13 April 2026
// For a person: the month as a word. Unambiguous everywhere.
new Intl.DateTimeFormat("en-GB", {
day: "numeric", month: "long", year: "numeric", timeZone: "UTC",
}).format(due); // "13 April 2026"
// Where a numeric date is unavoidable: ISO ordering, four-digit year.
due.toISOString().slice(0, 10); // "2026-04-13"
// Not this: ambiguous on any day of the month up to the twelfth, and
// silent about it on every other day.
// `${d.getDate()}/${d.getMonth() + 1}/${d.getFullYear()}`What people do instead
Using the numeric form in a table because the column is narrow, while using the written form elsewhere in the same document. The narrow column is where the due dates are, so the ambiguity is concentrated in exactly the field where it costs the most.
How to find out rather than assume
Search the rendered document for any date where the day is twelve or lower and ask a colleague from a different convention to read it aloud. If their reading differs from yours, that date is a defect. Then check the column still fits with the longest month name.
Where the API sits in this
Nowhere, and that is worth saying plainly. This API renders HTML to PDF. By the time markup reaches it, every value in it is already a string that somebody's code produced, so there is no locale option on the render because there would be nothing for one to do. What the render controls is the page: the size, the margins, and whether the formatted value still fits the column it landed in. That is why each of these pages has a paragraph about the layout consequence, because that is the half a document adds to the general problem.
Frequently asked
Should the document use the sender's conventions or the reader's?
That is a decision rather than a fact, and the only wrong answer is not making it. The issuer's conventions are defensible for a document that is a record of what the issuer did. The recipient's are defensible for a document meant to be acted on. What fails is a document that mixes them, because a reader who sees two conventions on one page cannot tell which one any given figure is in.
Is it enough to set the document language?
No. A language attribute helps with hyphenation, with the assistive technology reading order and with anything that needs to know what language the text is in, and it changes none of the values. A date formatted as 03/04/2026 is exactly as ambiguous in a document declared as English as in one declared as anything else. The values are formatted upstream.
Why does this belong in a document reference rather than a general one?
Because a document cannot be re-rendered by its reader. On a screen a wrong format is annoying and a user can often change a setting. On paper the format is final, the layout was tuned to the string lengths of one language, and a value that grew by a few characters can push a table onto another page. The formatting problem and the pagination problem are the same problem here.
Related formatting topics
The defects that travel together, then the rest of the same group.
A timestamp with no offset is a timestamp with no meaning
A time printed in a document without saying which zone it is in, which is unresolvable by the reader and frequently wrong by a day at the boundaries.
Translated labels that no longer fit the column they were sized for
The same label in another language is frequently longer, and a layout tuned to the original wraps, clips or reflows once the translation goes in.
Alphabetical order that is not alphabetical to the reader
The order a list is sorted into, which is defined by the language rather than by the byte values of the characters.
Payment terms line, as a layout problem
The block this value lands in, and what it takes to make it fit.
Every formatting and locale topic
The full list, grouped by money, time, identity and generated language.
Writing systems in a PDF
The other half: whether the glyphs of a script come out shaped and joined correctly.
Values are formatted by your code before they reach the markup, so every fix on this page is upstream of the render. What the render decides is whether the result still fits.