Date.prototype.toLocaleDateString()
Formats the date portion using a locale's conventions, with optional time zone and style control.
toLocaleDateString()
toLocaleDateString(locales)
toLocaleDateString(locales, options)- Added in JavaScript ES3 (1999); locales and options added in ECMA-402 (2012)
Parameters
| Parameter | Type | Description |
|---|---|---|
$localesoptional | string | string[]= undefined | A BCP 47 language tag, or an array of such tags, matching the locales parameter of the Intl.DateTimeFormat() constructor. In implementations without Intl.DateTimeFormat support this parameter is ignored and the host's locale is usually used. |
$optionsoptional | object= undefined | An object adjusting the output format, matching the options parameter of the Intl.DateTimeFormat() constructor. timeStyle must be undefined. If weekday, year, month and day are all undefined, then year, month and day are set to "numeric". Ignored in implementations without Intl.DateTimeFormat support. |
Return value
stringA string representing the date portion of the given date according to language-specific conventions. In implementations with Intl.DateTimeFormat, equivalent to new Intl.DateTimeFormat(locales, options).format(date) with options normalized as described.
Errors
Throws a TypeError if the timeStyle option is defined, and a RangeError if locales contains a malformed language tag or an option is given an unsupported value.
Changelog
- PHP ECMA-402 (2012)The locales and options parameters were added; before that the output was entirely implementation-defined.
- PHP ECMA-402 2020dateStyle and timeStyle were introduced; passing timeStyle here throws a TypeError, since this method formats only the date portion.
toLocaleDateString() is the method for dates a person will read. It knows that en-US writes 5/9/2024 while en-GB writes 09/05/2024, and it handles non-Gregorian calendars, translated month names and right-to-left scripts without any work from you.
Always pass a locale and a timeZone
With no arguments, the output depends on the machine running the code — a CI box, a server and a user's laptop will disagree. Two consequences follow. First, never write a test or a snapshot against the default output. Second, never compare the result to a hardcoded string: engines legitimately differ within the same locale, and modern ICU inserts narrow no-break spaces (U+202F) where you would expect a normal space.
d.toLocaleDateString("en-US", { timeZone: "UTC" })The timeZone option matters as much as the locale. Without it, a timestamp near midnight renders as a different calendar day depending on where the code runs.
Options replace, they do not extend
The moment you supply any of weekday, year, month or day, the numeric defaults for the others are not applied — you get only the components you named. Ask for { month: "long" } and you get just the month name. Use dateStyle ("full", "long", "medium", "short") when you want a whole sensible date rather than assembling fields.
timeStyle is rejected with a TypeError; use toLocaleString() if you need the time too.
Example
When to use it
- Rendering a due date in the visitor's language and regional order
- Showing a UTC timestamp as the calendar day in a chosen office's time zone
- Producing a long-form date like "9 May 2024" without hand-written month tables
Frequently asked questions
Why does the same code print a different date format on another machine?
Because with no locales argument the host's default locale and time zone are used. Pass an explicit locale string and a timeZone option to make output reproducible.
How do I show a date in a specific time zone?
Pass timeZone in the options object, for example toLocaleDateString("en-US", { timeZone: "Asia/Tokyo" }). Any IANA zone name works, and it changes which calendar day is displayed for instants near midnight.
Why does my string comparison against the formatted date fail?
Modern ICU uses narrow no-break spaces and other invisible characters, and output can legitimately differ between engines for the same locale. Compare Date values or ISO strings instead of formatted output.
More examples
The time zone decides the day
One instant, three calendar days. Tokyo is already on the 16th while New York is still on the 15th, which is why omitting timeZone makes output depend on where the code runs.
const instant = new Date("2024-01-15T23:30:00Z");
for (const zone of ["UTC", "America/New_York", "Asia/Tokyo"]) {
console.log(zone, instant.toLocaleDateString("en-CA", { timeZone: zone }));
}Reuse a formatter in loops
The formatter is built once and reused, producing identical output to the per-call method at a fraction of the cost.
const fmt = new Intl.DateTimeFormat("fr-FR", {
dateStyle: "medium",
timeZone: "UTC",
});
const days = [0, 1, 2].map((n) => new Date(Date.UTC(2024, 6, 1 + n)));
console.log(days.map((d) => fmt.format(d)));
console.log(fmt.format(days[0]) === days[0].toLocaleDateString("fr-FR", { dateStyle: "medium", timeZone: "UTC" }));Partial option sets
Naming one component suppresses the numeric defaults for the rest, so { month: "long" } yields the month alone. Passing timeStyle throws a TypeError because this method formats only the date.
const d = new Date(Date.UTC(2024, 4, 9));
const z = { timeZone: "UTC" };
console.log(d.toLocaleDateString("en-US", z));
console.log(d.toLocaleDateString("en-US", { ...z, month: "long" }));
console.log(d.toLocaleDateString("en-US", { ...z, month: "long", year: "numeric" }));
try {
d.toLocaleDateString("en-US", { timeStyle: "short" });
} catch (err) {
console.log(err.constructor.name);
}
Discussion