Dates and numbers Required
Keep calendar dates as dates
Keep a value with no time of day, such as a due date, as a plain YYYY-MM-DD date everywhere. Never turn it into a moment in time.
How to do it
In JavaScript, new Date('2026-03-05') means midnight UTC, which shows as 4 March west of UTC. Use Temporal.PlainDate. Firefox 139 and Chrome 144 ship it, but Safari did not in October 2026, so load a polyfill such as @js-temporal/polyfill there. Without it, split the string and format with timeZone: 'UTC'. Send the date input's value string as it is. Store it in a date column, not a timestamp.
Example
import { Temporal } from '@js-temporal/polyfill';
export function formatCalendarDate(value: string, locale: string): string {
return Temporal.PlainDate.from(value).toLocaleString(locale, { dateStyle: 'long' });
}
export function formatCalendarDateWithoutTemporal(value: string, locale: string): string {
const [year, month, day] = value.split('-').map(Number);
return new Intl.DateTimeFormat(locale, { dateStyle: 'long', timeZone: 'UTC' }).format(Date.UTC(year, month - 1, day));
}
from datetime import date
from babel.dates import format_date
due = date.fromisoformat("2026-03-05")
print(format_date(due, "long", locale="en_GB"))
How to check
Run the date tests with TZ=America/Los_Angeles and TZ=Pacific/Auckland. A due date of 2026-03-05 saves and shows as 5 March in both.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers app interface playbook: https://agentwranglers.se/playbook/app-ui/dates-and-numbers/calendar-dates.