Dates and data
Format dates with an explicit time zone
Show one JavaScript timestamp in London and Paris, keep UTC output separate and test seasonal differences.
A timestamp and its displayed time answer different questions. A timestamp can identify one instant. A formatted label shows that instant using a locale and a time zone. Making those choices explicit helps when an event, support message or activity log needs to make sense to people in different places.
Begin with an unambiguous instant
Start with a timestamp that includes an offset. In this example, the final Z identifies UTC. The Date object represents the instant, while the formatter controls the label shown to the reader.
const instant = new Date("2026-01-15T12:00:00Z")
function showIn(timeZone) {
return new Intl.DateTimeFormat("en-GB", {
timeZone,
dateStyle: "medium",
timeStyle: "short"
}).format(instant)
}
console.log(showIn("Europe/London")) // 15 Jan 2026, 12:00
console.log(showIn("Europe/Paris")) // 15 Jan 2026, 13:00These labels describe the same instant. Changing the formatter’s timeZone option does not move the event. The en-GB locale selects presentation conventions, and the separate timeZone setting selects the zone used for the displayed date and time. Locale and time zone should not be treated as interchangeable settings.
Choose the display rules for the task
A customer booking page may need the business location’s time zone. An internal activity feed may use the viewer’s chosen zone. A shared diagnostic log may favour UTC. Choose deliberately and show the zone where a reader could otherwise misunderstand the time. The right choice depends on what the label is helping someone do.
For example, a workshop in London should not silently display a Paris visitor’s local time as though it were the workshop’s opening time. State that the booking uses London time. If you also provide a visitor-local preview, label both outputs. A format option alone cannot explain that distinction to the reader.
For a repeated list of events using the same display settings, create one formatter and reuse it. That keeps the choices in one place and avoids slightly different formatting between nearby components. Pass each valid Date value to its format method.
Use ISO output when you need UTC text
The toISOString method returns a UTC representation. It is useful for inspecting an instant or sending a timestamp where the receiving system expects that representation. It is not a shortcut for displaying a local appointment time.
console.log(instant.toISOString())
// 2026-01-15T12:00:00.000ZKeep the meaning of each field clear. An order creation timestamp can describe a past instant. A shop’s daily opening time describes a recurring local rule. Storing only one UTC timestamp does not define the full schedule for a business that opens at the same local time throughout the year. A scheduling model needs to represent the rule as well as the relevant zone.
Check a winter date and a summer date
Time zones can have seasonal offset changes. Test the dates your application actually handles instead of applying one fixed number of hours to every event. The winter example above should be complemented with a summer input, using the same named zones.
const summer = new Date("2026-07-15T12:00:00Z")
const london = new Intl.DateTimeFormat("en-GB", {
timeZone: "Europe/London",
hour: "2-digit",
minute: "2-digit",
hourCycle: "h23"
})
console.log(london.format(summer)) // 13:00A fixed rule that always displays London as UTC would be wrong for this example. Named time zones let the runtime apply its time-zone data. Keep your runtime and its data current, and include tests around any transition dates that matter to your service. A display example is not a complete appointment scheduler.
Reject invalid values before formatting
An invalid Date should produce a clear error path in your application. Check the numeric time value before calling code that expects a valid instant. Also decide which input format your interface accepts. A placeholder such as 03/04/2026 leaves the month and day ambiguous across common conventions.
function validInstant(text) {
const value = new Date(text)
return Number.isNaN(value.getTime()) ? null : value
}
console.log(validInstant("not-a-date")) // nullThis small helper rejects an invalid parse, but it is not a strict format validator. If your interface requires a full ISO timestamp with an offset, enforce that contract separately. Do not accept a loosely parsed string and then assume the user intended the resulting date. Test missing offsets and date-only values as their own cases.
For the underlying behaviour, read MDN’s Intl.DateTimeFormat reference and the toISOString reference. Keep the original instant, name the display zone and test the dates that matter to your application.