🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Global_Objects › Intl › DateTimeFormat › DateTimeFormat
Intl.DateTimeFormat() constructor - JavaScript - MDN Web Docs
January 21, 2026 - You can format different object types depending on which of the style shortcut options you include: If the dateStyle is specified, then you can format Temporal.PlainDate, Temporal.PlainYearMonth, and Temporal.PlainMonthDay objects. If the timeStyle is specified, then you can format Temporal.PlainTime objects. If either dateStyle or timeStyle is specified, then you can format Temporal.PlainDateTime and Date objects. A new Intl.DateTimeFormat object.
🌐
Devhints
devhints.io › hidden › intl.datetimeformat cheatsheet
Intl.DateTimeFormat cheatsheet
April 20, 2018 - console.log(new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'numeric', day: 'numeric' }).format(date)) // → '12/19/2012' To specify options without a locale, use 'default' as a locale.
Discussions

Ability to specify a custom format for Intl.DateTimeFormat
(Apologies if this is the wrong way to approach this or if it's been covered before, though I couldn't see it if so) As best I can tell, Intl.DateTimeFormat doesn't have any ability to ... More on github.com
🌐 github.com
18
March 10, 2021
Intl.DateTimeFormat() with format options doesn't work for 'it-CH'
I get a locale from the server and try to format a given date based on this locale formatting options and additional options. It works with all locales, but it-CH date = new Date(2010,0,1) new Intl. More on stackoverflow.com
🌐 stackoverflow.com
Intl.DateTimeFormat options hash: Getting leading zeros with '2-digit'
When I checked the specs, it has defined an algorithm which can be used to implement Intl.DateTimeFormat functionality. More on stackoverflow.com
🌐 stackoverflow.com
What exactly does the timeZone option do in Intl.DateTimeFormat()
Intl.DateTimeFormat('en-GB', { hour: 'numeric', minute: 'numeric', second: 'numeric', timeZone: 'GMT' }).format(timestamp)} I do not fully understand, why I need to pass the option timeZone: 'GMT' for "Greenwich Mean Time' to get the correct time on the frontend. More on stackoverflow.com
🌐 stackoverflow.com
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Global_Objects › Intl › DateTimeFormat
Intl.DateTimeFormat - JavaScript | MDN
The initial value of the [Symbol.toStringTag] property is the string "Intl.DateTimeFormat". This property is used in Object.prototype.toString(). ... Getter function that formats a date according to the locale and formatting options of this DateTimeFormat object.
🌐
GitHub
github.com › prantlf › intl-datetimeformat-options
GitHub - prantlf/intl-datetimeformat-options: Provides localized date/time format patterns for styles full, long, medium and short, using Intl.DateTimeFormat.
Provides localized date/time format patterns for styles full, long, medium and short, using Intl.DateTimeFormat. - prantlf/intl-datetimeformat-options
Author   prantlf
🌐
Format.JS
formatjs.github.io › docs › polyfills › intl-datetimeformat
Intl Datetimeformat | FormatJS
Proposal: Intl.DateTimeFormat dateStyle & timeStyle ... new Intl.DateTimeFormat('en', {dateStyle: 'long', timeStyle: 'short'}) // "January 1, 2024 at 12:00 PM"
🌐
TC39
tc39.es › proposal-intl-datetime-style
dateStyle and timeStyle options for DateTimeFormat
July 21, 2020 - This proposal adds two options to Intl.DateTimeFormat: dateStyle and timeStyle. These options give a compact way to request the appropriate, locale-specific way to ask for a date and time of given lengths.
🌐
DEV Community
dev.to › diorla › a-guide-to-date-and-time-formatting-in-javascript-2ol2
A Guide to Date and Time Formatting in JavaScript - DEV Community
September 3, 2023 - One of the most powerful features of Intl.DateTimeFormat is the ability to customize how dates and times are formatted. You can do this by providing an options object as the second argument when creating an instance of Intl.DateTimeFormat.
🌐
CodingNomads
codingnomads.com › formatting-dates-and-times-javascript-intl
Formatting Dates and Times in JavaScript Using Intl
To tailor the output of your dates by passing an options object with properties like dateStyle, timeStyle, and timeZone to the DateTimeFormat constructor. About the flexibility of customization for various date components such as weekday, year, ...
🌐
GeeksforGeeks
geeksforgeeks.org › javascript › javascript-intl-datetimeformat-format-method
JavaScript Intl DateTimeFormat format() Method - GeeksforGeeks
July 12, 2025 - const Geeks = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; const dateformat = new Date(1997, 06, 30); const dateTimeFormat4 = new Intl.DateTimeFormat('hi', Geeks); console.log(dateTimeFormat4.format(dateformat)); const dateTimeFormat2 = new Intl.DateTimeFormat('en-GB', Geeks); console.log(dateTimeFormat2.format(dateformat)); const dateTimeFormat1 = new Intl.DateTimeFormat('sr-RS', Geeks); console.log(dateTimeFormat1.format(dateformat)); const dateTimeFormat3 = new Intl.DateTimeFormat('en-US', Geeks); console.log(dateTimeFormat3.format(dateformat));
Find elsewhere
🌐
GitHub
github.com › tc39 › ecma402 › issues › 554
Ability to specify a custom format for Intl.DateTimeFormat · Issue #554 · tc39/ecma402
March 10, 2021 - As best I can tell, Intl.DateTimeFormat doesn't have any ability to specify the exact format string to use. Instead it is always based upon the locale with the ability to customise individual portions of the produced string.
Author   sazzer
🌐
DEV Community
dev.to › josephciullo › crush-date-and-time-formatting-natively-unleash-the-hidden-power-of-intldatetimeformat-4b2g
Crush Date and Time Formatting Natively: Unleash the Hidden Power of Intl.DateTimeFormat - DEV Community
January 27, 2025 - Explore the simplicity and power of Intl.DateTimeFormat with these foundational examples. We'll demonstrate how to create a formatter for default and custom formats that can be reused across your application. If no options are provided, the formatter uses the default format of the selected locale.
Top answer
1 of 2
2

You can solve this problem by using the intl polyfill module to completely replace NodeJS’s implementation of intl.

First run npm i --save intl

Then you need to replace Intl by polyfill:

Intl = require("intl")

That's it. Now you can try:

const date = new Date();
const options = {
        year: 'numeric',
        day: 'numeric',
        month: 'numeric',
        hour: 'numeric',
        minute: 'numeric'
    };
const dateFormatted = new Intl.DateTimeFormat('pt-BR', options).format(date);
console.log(dateFormatted);

// expected output: 24/09/2019 17:43

2 of 2
1

Unfortunately the actual formatting of dates by toLocaleString is largely implementation dependent, so while it may be consistent for the most common languages and variants, it's not so good for those that are less common or where multiple date formats are commonly used (which is the case where I live).

The situation is quite complex. The "locale" is a BCP 47 language tag. The list of tags and subtags is maintained by IANA and changes from time–to–time. Further, the mapping of formats to tags and subtags is implementation dependent.

The bottom line is that there is uncertainty over what format should apply to a particular language and variant, and a huge number of local languages and variants (e.g. tribal languages) are not supported at all. So don't rely on toLocaleString doing all the work and getting it right all the time.

An alternative to leaving it all up to the implementation is to manually format the date in an unambiguous format using toLocaleString for the language of the individual components. That way where a specific language isn't supported, you can fall back to the browser default language (see PPS below) and be confident that what you're putting on the page is clear and not leaving it entirely to the implementation, e.g.

function getFormattedDate(d, lang){
  return d.getDate().toLocaleString(lang) + ' '
    + d.toLocaleString(lang, {month:'long'}) + ', '
    + d.toLocaleString(lang, {year:'numeric'});
}

var d = new Date();
['it-CH', 'en-GB', 'ar-EG', 'zu-ZA', 'hz', undefined].forEach(
  lang => console.log((lang||'Default') +
          ': ' + getFormattedDate(d, lang))
);

Don't get too hung up over supporting every possible format and language variant. It's far more important to ensure dates are unambiguous than whether the components are separated by commas, dashes, slashes or whatever the local variant uses customarily. As I look at formal correspondence in my locale, dates are represented in 3 or 4 different formats, often two different formats are used on the same page (e.g. in headers, text and tabular data).

PS: You should also test for support for toLocaleString before using it.

PPS: It would be really good if there was a way to test if a language tag is supported before using it, but as far as I can tell that's not possible. E.g. in the example above, "hz" is Herero, a language spoken by a particular ethnic group in southern Africa and likely not supported by any browser, so it should fall back to the browser default language.

Top answer
1 of 2
25

This will work if you set hour12 property to false. i.e.

Intl.DateTimeFormat('en-US', {
    weekday: 'long',
    year: 'numeric',
    month: 'long',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false     // setting 24 hour format 
}).format(807959700000);

It works for both 2am and also 2pm(14hr). But I know the same should work for 12 hour format too, but it is not. I checked in both chrome and firefox browsers.

When I checked the specs, it has defined an algorithm which can be used to implement Intl.DateTimeFormat functionality. I saw there were many special cases handled when hour12 property to set true, and one of the last step is

  1. If dateTimeFormat has an internal property [[hour12]] whose value is true, then
    • If pm is true, then let fv be an implementation and locale dependent String value representing “post meridiem”; else let fv be an implementation and locale dependent String value representing “ante meridiem”.
    • Replace the substring of result that consists of "{ampm}", with fv.

So I think, the Intl.DateTimeFormat initially works with date object, later at step(8), it applies this step to put am/pm information.

During this step, may be 2-digits information specified in Intl.DateTimeFormat is not considered, but it has to be. I think this is a valid bug and it is already raised https://code.google.com/p/chromium/issues/detail?id=527926.


PS: I'm not saying issue is in specs, as described in the ECMAScript Language Specification,

Algorithms are used to precisely specify the required semantics of ECMAScript constructs, but are not intended to imply the use of any specific implementation technique.

2 of 2
21

This still does NOT work on Chrome Version 79 or Node.js v13.7.0!

They both ignore the 2-digit format. Here's a quick test case:

d = new Date('2020-01-01T03:04:09Z') 
new Intl.DateTimeFormat('en', { minute: '2-digit'}).format(d) //"4"

//should return "04" but it actually returns "4"

Please comment on this post when you see it's fixed.


Update 06-22-2021:

Still doesn't work on Chrome Version 91.0.4472.106 Node.Js v14.15.4


Update 12-09-2022:

Tested on Chrome Version 108.0.5359.98. Still doesn't work.


Update 07-31-2023:

Tested on Chrome Version 115.0.5790.110. Still doesn't work.


Update 01-04-2025:

Tested on Chrome Version 131.0.6778.205. Still doesn't work.

🌐
Medium
medium.com › @vandanacherukuru › javascript-internalization-intl-datetimeformat-e8c0bb91a904
JavaScript Internationalization (Intl.DateTimeFormat) | by Vandana Rao Cherukuru | Medium
April 1, 2025 - Takes a Date object as input to its format() method. You need a Date object to use with Intl.DateTimeFormat(). Provides highly customizable output based on locale and options.
🌐
DEV Community
dev.to › rsa › perfectly-localizing-date-time-with-intl-datetimeformat-ack
Perfectly localizing date & time with Intl.DateTimeFormat - DEV Community
December 3, 2020 - All of these functions take the same attributes the constructor for DateTimeFormat takes: locale and options. Let's see what those are. The first parameter, locales, is one or a list of possible locales for negotiation. Language negotiation is an intricate subject, and I don't want to dive into it yet, so check the MDN reference if you need details. Here are some examples of how the locale will change the output: const dtf = new Intl.DateTimeFormat(); dtf.format(date); //=> "11/5/2020" // equivalent to date.toLocaleDateString()
🌐
Rafaelcamargo
rafaelcamargo.com › blog › mastering-date-formatting-using-intl-date-time-format-in-javascript
Mastering date formatting using Intl.DateTimeFormat in JavaScript
May 29, 2024 - If you need a date format that includes text and not just digits, look at the possibilities that the month option offers. const date = new Date(2024, 3, 29, 0); const opts = { day: 'numeric', year: 'numeric' }; Intl.DateTimeFormat('en-US', { ...opts, month: 'long' }).format(date); // → April 29, 2024 Intl.DateTimeFormat('en-US', { ...opts, month: 'short' }).format(date); // → Apr 29, 2024 Intl.DateTimeFormat('en-US', { ...opts, month: 'narrow' }).format(date); // → A 29, 2024
🌐
Tryhoverify
tryhoverify.com › blog › intldatetimeformat-for-localization
Intl.DateTimeFormat for Localization | Hoverify
May 1, 2025 - The Intl.DateTimeFormat constructor lets you adjust the format with two main options: dateStyle and timeStyle.
Top answer
1 of 1
9

Problem: Variable has too broad of a type

What you are experiencing here is a common problem when dealing with functions that require string literal types in their arguments. It's nothing specific to Intl.DateTimeFormat. You can read the docs on Literal Inference for more info.

Let's take a look at what your error is telling you:

Argument of type '{ year: string; month: string; day: string; weekday: string; }' is not assignable to parameter of type 'DateTimeFormatOptions'.

Types of property 'weekday' are incompatible.

Type 'string' is not assignable to type '"short" | "long" | "narrow"'.ts(2345)

The type of your option.weekday is inferred as string. This is not specific enough for the Intl.DateTimeFormat constructor, which only allows three possible string literal values: "short" | "long" | "narrow".

The value of your option variable is fine. But TypeScript only looks at types, not values.

When you write your assignment statement like this:

const option = {
    year: "numeric",
    month: "short",
    day: "numeric",
    weekday: "long",
}

TypeScript infers the type as:

const option: {
    year: string;
    month: string;
    day: string;
    weekday: string;
}

We need to create your variable in a way that will give it a narrower type.

Solution 1: Declare the type

We know from your error that the type which your option variable needs to fit is Intl.DateTimeFormatOptions. We can use that type when you create the option variable.

const option: Intl.DateTimeFormatOptions = {
    year: "numeric",
    month: "short",
    day: "numeric",
    weekday: "long",
}

TypeScript will check each of the properties of your object to make sure that they are assignable to the constraints of the Intl.DateTimeFormatOptions type.

If you provide an invalid value, like this:

const option: Intl.DateTimeFormatOptions = {
    weekday: "numeric",
}

You'll see a red underline on the weekday property. I prefer this approach for that reason -- it is easier to see exactly where the problems are. For weekday: "numeric" your error message would be:

Type '"numeric"' is not assignable to type '"long" | "short" | "narrow" | undefined'

Solution 2: as const

You can change the way that TypeScript infers the type by using an as const statement when you create your variable. This tells TypeScript to treat all properties of your object as their literal types (explained here).

const option = {
    year: "numeric",
    month: "short",
    day: "numeric",
    weekday: "long",
} as const;

TypeScript infers the type as:

const option: {
    readonly year: "numeric";
    readonly month: "short";
    readonly day: "numeric";
    readonly weekday: "long";
}

Each property has a string literal type like "long" rather than just string.

Assuming that your values are valid, these literal types will be assignable to the broader Intl.DateTimeFormatOptions type. For example, "long" is assignable to the union type '"short" | "long" | "narrow"' on the weekday property.

Top answer
1 of 4
27

This is very close to being off–topic as opinion based, but here goes anyway.

Which one of these should I use?

Date.prototype.toLocaleString was originally solely implementation dependent and varied quite a bit across browsers. When support for the Intl object was added (ECMAScript 2015, ed 6) then toLocaleString was allowed to support the same options. While support isn't mandated by ECMA-262, probably all current implementations support it.

Note that this did not remove the allowed implementation variability, it just provided some formatting options based on language, region and dialect (and also timezone options based on the IANA time zone database identifiers and values).

The Intl object (and hence toLocaleString) is based on ECMA-402, which doesn't strictly specify formatting, so there is still some room for implementations to differ. The biggest differences are in regard to timezone names (for which there is no standard) and placement of commas, spaces, etc.

However, for most practical purposes, whether you use the Intl object or toLocaleString is up to you, I don't think there's any technical reason to prefer one over the other. While the results for both should be identical for a particular implementation, don't expect the resulting string to be exactly identical across implementations or to conform to a particular format for a given BCP 47 language tag.

2 of 4
11

If you re-use the same format a lot of times, re-using Intl.DateTimeFormat object seems to be better from a performance perspective.

const format =  {
    weekday: 'long',
    month: 'long',
    day: '2-digit',
};
const dateTimeFormat = new Intl.DateTimeFormat('en', format);
const start1 = performance.now();
for (let i = 0; i < 10000; i++) dateTimeFormat.format(new Date());
console.log('re-use Intl.DateTimeFormat', performance.now() - start1);

const start2 = performance.now();
for (let i = 0; i < 10000; i++) new Date().toLocaleString('en', format);
console.log('use toLocaleString', performance.now() - start2);

When I run this snippet in Chrome 105, it gives me a result like this:

re-use Intl.DateTimeFormat 17.299999952316284
use toLocaleString 876.0999999046326