Locale-aware date/time formatting
Writing a timestamp the way the reader's region writes it: 3/4 is April in London and March in Chicago, and Europe wants 15:00 not 3 PM.
See it
What it is
The same instant gets written differently everywhere: 3/4/2026 means March 4th in the US and April 3rd in most of the world, Japan leads with the year, and much of Europe wants 15:00 rather than 3:00 PM. Locale-aware formatting means you never assemble a date string by hand. You store a real instant as UTC (ISO 8601) and let Intl.DateTimeFormat render it with the reader's locale and their IANA time zone ('Europe/Berlin', not 'UTC+1'). Not everything is an instant, though: a birthday is a date with no time zone at all, and a 9am recurring meeting is a civil time that belongs to a named zone. Convert those to UTC and you will watch birthdays slide a day.
In practice, ask for a style rather than a pattern: dateStyle 'medium' and timeStyle 'short' give you a sensible, translated, region-correct result in one line. Reserve explicit option objects (weekday, month: 'long') for cases where you genuinely need a specific shape. For 'yesterday' and 'in 3 hours', use Intl.RelativeTimeFormat instead of subtracting numbers yourself.
The real gotcha is the all-numeric date. 04/03/26 is genuinely ambiguous to half your users, so anywhere the date carries weight (invoices, deadlines, deletion warnings) spell the month out. Second trap: Slavic and Finnish month names change form depending on whether they stand alone or sit inside a full date, so slicing a month name out of one formatter and pasting it into your own template produces sentences that read as broken to native speakers.
Ask AI for it
Make every date and time in this app locale-aware. First sort the values into three kinds and store each correctly: actual instants as UTC ISO 8601 timestamps, date-only values such as birthdays and invoice dates as plain ISO dates with no time zone, and scheduled local times with their IANA zone alongside. Do not flatten date-only or civil-time values into UTC instants. Render each kind at the component boundary with Intl.DateTimeFormat using the active app locale and the time-zone semantics that kind deserves. Use dateStyle 'medium' plus timeStyle 'short' by default so the month is spelled out and the 12/24-hour choice follows the locale, and use Intl.RelativeTimeFormat for 'x minutes ago' strings. Remove all manual formatting: no toLocaleDateString('en-US') hardcoding, no slice or padStart on date parts, no concatenated MM/DD/YYYY templates.