Description
Bug Description
When using the Intl.DateTimeFormat
API in JavaScript to format dates and times, there is an inconsistency in the behavior when the hour12
option is set to true
or when the provided locale uses a 12-hour clock by default, in combination with the hour
option set to "2-digit"
.
Note: This bug seems to effect all locales but I only tested the ones below:
- English:
en-US
(12 hours by default) - German:
de-DE
(24 hours by default) - Arabic:
ar-LB
(non-latin characters)
Steps To Reproduce
- Use the
Intl.DateTimeFormat
API to format a date. - Set the
hour
option to"2-digit"
. - Set the
hour12
option totrue
or provide a locale that uses a 12-hour clock by default (e.g., "en-US"). - Observe that single-digit hours are formatted without leading zeros.
Run the following code example:
const hour1 = new Intl.DateTimeFormat("en-US", {
hour: "2-digit",
}).format(new Date("2024-10-30 19:00"));
console.log(hour1);
// OR
const hour2 = new Intl.DateTimeFormat("fr-FR", {
hour: "2-digit",
hour12: true,
}).format(new Date("2024-10-30 19:00"));
console.log(hour2);
Assert that it prints 7 PM
instead of 07 PM
.
The Expected Behavior
When the hour
option is set to "2-digit"
, it is expected that the formatted hour will always have two digits, including a leading zero for single-digit hours (e.g., "01", "02", ..., "12").
Actual Behavior
When hour12
is set to true
or the provided locale uses a 12-hour clock by default, the "2-digit"
option for hour
is ignored. The formatted hour is displayed with a single digit for single-digit hours (e.g., "1", "2", ..., "12") without a leading zero.
This bug only affects the 12-hour clock format. When using a 24-hour clock format, the "2-digit"
option works as expected, displaying hours with leading zeros (e.g., "00", "01", ..., "23").
Temporary Example Workaround
function workaround(date: Date) {
const locale = "en-US";
const parts = new Intl.DateTimeFormat(locale, {
hour: "2-digit",
minute: "2-digit",
hour12: true,
}).formatToParts(date);
const hourPart = parts.find((part) => part.type === "hour")!;
const hourIn24Format = new Intl.DateTimeFormat(locale, {
hour: "2-digit",
hour12: false,
})
.formatToParts(date)
.find((p) => p.type === "hour")!.value;
if (hourPart.value !== hourIn24Format) {
const tmp = new Date(date);
tmp.setHours(tmp.getHours() % 12);
const hour24 = new Intl.DateTimeFormat(locale, {
hour: "2-digit",
hour12: false,
}).format(tmp);
hourPart.value = hour24;
}
return parts.map((part) => part.value).join("");
}
const hour1 = new Intl.DateTimeFormat("en-US", {
hour: "2-digit",
minute: "2-digit",
hour12: true,
}).format(new Date("2024-10-30 19:00"));
const hour2 = workaround(new Date("2024-10-30 19:00"));
console.log(hour1, hour2); // prints 7:00 PM 07:00 PM
Note: The above isn't simply padding the string with zeros because that only works in latin languages.
Output of npx react-native info
:
Note: The output below is from the project I am currently working on using expo.
I did created a blank new project with "react-native": "^0.75.4"
(latest version ATTOW) and the issue persists.
System:
OS: Linux 6.9 Pop!_OS 22.04 LTS
CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Memory: 2.24 GB / 15.49 GB
Shell:
version: 3.3.1
path: /usr/bin/fish
Binaries:
Node:
version: 20.15.0
path: ~/.nvm/versions/node/v20.15.0/bin/node
Yarn:
version: 1.22.22
path: ~/.nvm/versions/node/v20.15.0/bin/yarn
npm:
version: 10.8.1
path: ~/.nvm/versions/node/v20.15.0/bin/npm
Watchman:
version: 4.9.0
path: /usr/bin/watchman
SDKs:
Android SDK: Not Found
IDEs:
Android Studio: AI-241.15989.150.2411.11792637
Languages:
Java:
version: 17.0.12
path: /usr/bin/javac
Ruby:
version: 3.0.2
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 18.2.0
wanted: 18.2.0
react-native:
installed: 0.74.5
wanted: 0.74.5
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: false
iOS:
hermesEnabled: Not found
newArchEnabled: false
Activity