facebook / facebook/hermes

Intl.DateTimeFormat does not format 2-digit hours correctly

Open
#1,537 4 comments 0 reactions 0 assignees View on GitHub
bug Intl
Dominant language
JavaScript
Stars
11.3k
Forks
859
Avg merge
1h 30m
Merged PRs (30d)
3

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
1. Use the `Intl.DateTimeFormat` API to format a date.
2. Set the `hour` option to `"2-digit"`.
3. Set the `hour12` option to `true` or provide a locale that uses a 12-hour clock by default (e.g., "en-US").
4. Observe that single-digit hours are formatted without leading zeros.

Run the following code example:
```js
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
```ts
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
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.