Format Time Only Without the Date in JavaScript

To show only the time, give Intl.DateTimeFormat just the time fields (hour, minute) plus an explicit timeZone, or use timeStyle with no dateStyle. Part of Mastering Intl.DateTimeFormat Options.

Why this scenario is tricky

Showing just a time — "2:30 PM" with no date — sounds like it should be simpler than formatting a full timestamp, and the trap is that "the time" is meaningless without a zone even though the date is hidden. An instant does not have a time; it has a different time in every zone, so "what time is this" is only answerable relative to a zone. Omit the timeZone option and the formatter uses the host zone, so the same instant shows "2:30 PM" on a user's machine and "6:30 PM" on a UTC server — a discrepancy that is easy to miss precisely because the date, which would have made the zone dependence obvious, is not shown.

Intl.DateTimeFormat formats time-only output when you request only time fields (hour, minute, optionally second) or use the timeStyle shorthand, and the essential discipline is to always pair that with an explicit timeZone. The trickiness is entirely in remembering that hiding the date does not hide the zone dependence — if anything it obscures it — so the zone must be stated deliberately.

Slicing a time out of a formatted date string is fragile across locales. The right approach is to request only the fields you want; if you pass hour and minute and omit the date fields, the output is time-only, correctly localized and zoned.

Request fields, don't slice stringsString slicing breaks per localeRequest fields, don't slice stringsformatDate().split(',')[1]fragile, locale-specific{ hour, minute, timeZone }time-only, robustAsk Intl for exactly the fields you want to display.

Minimal working solution

Requesting { hour: 'numeric', minute: '2-digit', timeZone: 'Europe/Paris' } formats an instant as the Paris wall-clock time, "2:30 PM" for an instant that is 13:30 UTC. The timeStyle: 'short' shorthand is a convenient alternative that picks locale-appropriate time fields for you, but it still requires an explicit timeZone — the shorthand covers the fields, not the zone. Either way, the instant is projected into the named zone and only its time portion is rendered.

Choosing the zone is the real decision. For "when does this store open in its city," format in the store's zone; for "when is this meeting in my time," format in the viewer's zone. The same instant legitimately yields different time strings for different purposes, and making the zone an explicit argument is what lets one formatting function serve all of them correctly. Locale still controls the 12-versus-24-hour default and the AM/PM wording, so pass the user's locale alongside the purpose-driven zone.

const fmt = new Intl.DateTimeFormat('en-US', { hour: 'numeric', minute: '2-digit', timeZone: 'Europe/Paris' });
fmt.format(new Date('2024-03-15T13:30:00Z')); // '2:30 PM'

Time-only fieldshour+minute, no date fieldsTime-only fieldsinstanthour, minutetimeZone'2:30 PM'

Full production version

A production time formatter takes the instant, the locale, and the zone explicitly, caches the Intl.DateTimeFormat per (locale, zone, options), and returns the time string. Because time-only labels appear in dense lists — schedules, message timestamps, transit boards — the formatter cache matters for performance, and the explicit zone parameter prevents the whole class of "off by the offset" bugs that arise when the host zone leaks in. Keep the fields minimal (hour and minute, seconds only when needed) so the output stays scannable.

The subtle production case is a time that belongs to a civil context rather than an instant — "the shop opens at 9:00" as a policy independent of any particular day or the daylight-saving state. That is genuinely a PlainTime, and formatting it does not involve a zone at all, because it is not tied to an instant. Distinguish "the time of this specific moment, shown in a zone" (project an instant, pass a timeZone) from "a civil time-of-day" (a PlainTime, no zone), and format each with the right type — conflating them is how a fixed opening hour accidentally shifts with daylight saving.

// timeStyle is the shorthand; still pass a timeZone.
const fmt = new Intl.DateTimeFormat('ja-JP', { timeStyle: 'short', timeZone: 'Asia/Tokyo' });
fmt.format(new Date('2024-03-15T13:30:00Z')); // '22:30'

timeStyle shorthandtimeStyle without dateStyle = time onlytimeStyle shorthandinstanttimeStyleshorttimeZonelocalized time

Verification snippet

Time Only assertionsKey cases assert correctlyAssertions that prove the edge casehour+minute'2:30 PM'timeStyle shortlocale timeexplicit zonecorrect wall timeno date leakedtime only

Common pitfalls

Time Only pitfallsCommon mistakes and their fixesWrongRightslice a full date stringbreaks per localerequest hour/minute onlytime-only outputomit timeZonehost-zone timealways pass timeZonedeterministic

Frequently Asked Questions

How do I display only the time from a Date?

Create an Intl.DateTimeFormat with only time fields, such as { hour: 'numeric', minute: '2-digit', timeZone }, or use { timeStyle: 'short', timeZone }. Because you never request the date fields, the output is time-only and correctly localized.

Do I still need timeZone when formatting only the time?

Yes. Without an explicit timeZone the formatter uses the host zone, so a server prints a different time than the user's browser. Always pass the intended IANA zone even for time-only output.

How do I format only the time without the date in JavaScript?

Request only time fields from Intl.DateTimeFormat — { hour: 'numeric', minute: '2-digit', timeZone } — or use the timeStyle: 'short' shorthand, and always pass an explicit timeZone. For example, { hour: 'numeric', minute: '2-digit', timeZone: 'Europe/Paris' } renders a 13:30 UTC instant as '2:30 PM'. The zone is required because an instant has a different time in every zone.

Why do I still need a time zone when showing only the time?

Because an instant does not have a single time — it has a different one in every zone — so 'what time is this' is only answerable relative to a zone. Hiding the date actually obscures this dependence rather than removing it. Without an explicit timeZone the formatter uses the host zone, so the same instant shows different times on a user's machine and a UTC server.

When should I use PlainTime instead of formatting an instant?

Use PlainTime when the value is a civil time-of-day with no specific date or zone — like 'the shop opens at 9:00' as a policy. That is not tied to an instant, so formatting it involves no zone. Format an instant with an explicit timeZone when you mean 'the time of this specific moment shown in a place'. Conflating the two is how a fixed opening hour accidentally shifts with daylight saving.

Does locale affect a time-only display?

Yes. The locale controls the default 12-versus-24-hour convention and the AM/PM wording, so a French locale renders 24-hour time and a US locale 12-hour by default. Pass the user's locale alongside the purpose-driven zone, and let the locale choose the convention unless a design specifically requires a fixed one via hour12 or hourCycle.

Should the time be shown in the viewer's zone or the event's zone?

It depends on the question. For 'when is this meeting in my time', format in the viewer's zone; for 'when does this store open in its city', format in the store's zone. The same instant legitimately yields different time strings for different purposes, so make the zone an explicit argument driven by what the label means rather than defaulting to the host zone.