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
- 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,
Answer from rajuGT on Stack OverflowAlgorithms are used to precisely specify the required semantics of ECMAScript constructs, but are not intended to imply the use of any specific implementation technique.
Intl.DateTimeFormat options hash: Getting leading zeros with '2-digit'
datetime format - Intl.DateTimeFormat causes TypeScript error certain options - Stack Overflow
Ability to specify a custom format for Intl.DateTimeFormat
What exactly does the timeZone option do in Intl. ...
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
- 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.
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.
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
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.