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.

Answer from rajuGT on Stack Overflow
🌐
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
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Global_Objects › Intl › DateTimeFormat › DateTimeFormat
Intl.DateTimeFormat() constructor - JavaScript | MDN
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.
Discussions

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
datetime format - Intl.DateTimeFormat causes TypeScript error certain options - Stack Overflow
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. More on stackoverflow.com
🌐 stackoverflow.com
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
What exactly does the timeZone option do in Intl. ...
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
🌐
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.
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.

🌐
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 › 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()
🌐
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.
🌐
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.
Find elsewhere
🌐
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));
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.

🌐
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.
🌐
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, ...
🌐
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
🌐
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
🌐
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.
🌐
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.
🌐
Reality Ripple
udn.realityripple.com › docs › Web › JavaScript › Reference › Global_Objects › Intl › DateTimeFormat
Intl.DateTimeFormat - JavaScript
Dezember 2012" // an application may want to use UTC and make that visible options.timeZone = 'UTC'; options.timeZoneName = 'short'; console.log(new Intl.DateTimeFormat('en-US', options).format(date)); // → "Thursday, December 20, 2012, GMT" // sometimes you want to be more precise options = { hour: 'numeric', minute: 'numeric', second: 'numeric', timeZone: 'Australia/Sydney', timeZoneName: 'short' }; console.log(new Intl.DateTimeFormat('en-AU', options).format(date)); // → "2:00:00 pm AEDT" // sometimes you want to be very precise options.fractionalSecondDigits = 3; console.log(new Intl.D
🌐
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"
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.