Skip to content

Commit b18fb9c

Browse files
ajkleinV8 LUCI CQ
authored andcommitted
[intl] Revert date formatting behavior change from ICU 72
Replace U+202F with U+0020 after formatting date. This lets websites continue to work without any changes. This matches Firefox behavior, according to https://bugzilla.mozilla.org/show_bug.cgi?id=1806042#c17. (cherry picked from commit 90be99f) Bug: chromium:1414292, chromium:1401829, chromium:1392814 Change-Id: I1b2410fe45a5dc109628d8c44c24263edef7db3a Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4240359 Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Commit-Queue: Adam Klein <adamk@chromium.org> Cr-Commit-Position: refs/branch-heads/11.0@{#31} Cr-Branched-From: 06097c6-refs/heads/11.0.226@{#1} Cr-Branched-From: 6bf3344-refs/heads/main@{#84857}
1 parent 616e334 commit b18fb9c

11 files changed

Lines changed: 59 additions & 31 deletions

src/objects/js-date-time-format.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,11 @@ MaybeHandle<String> FormatDateTime(Isolate* isolate,
13951395
icu::UnicodeString result;
13961396
date_format.format(date_value, result);
13971397

1398+
// Revert ICU 72 change that introduced U+202F instead of U+0020
1399+
// to separate time from AM/PM. See https://crbug.com/1414292.
1400+
result = result.findAndReplace(icu::UnicodeString(0x202f),
1401+
icu::UnicodeString(0x20));
1402+
13981403
return Intl::ToString(isolate, result);
13991404
}
14001405

test/intl/date-format/date_style_time_style_hour_cycle.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ let noon = new Date(2019, 3, 4, 12);
88
let df_11_dt = new Intl.DateTimeFormat(
99
"en", {timeStyle: "short", dateStyle: "short", hourCycle: "h11"})
1010
assertEquals("h11", df_11_dt.resolvedOptions().hourCycle);
11-
assertEquals("4/4/19, 0:00\u202fAM", df_11_dt.format(midnight));
12-
assertEquals("4/4/19, 0:00\u202fPM", df_11_dt.format(noon));
11+
assertEquals("4/4/19, 0:00 AM", df_11_dt.format(midnight));
12+
assertEquals("4/4/19, 0:00 PM", df_11_dt.format(noon));
1313

1414
let df_12_dt = new Intl.DateTimeFormat(
1515
"en", {timeStyle: "short", dateStyle: "short", hourCycle: "h12"})
1616
assertEquals("h12", df_12_dt.resolvedOptions().hourCycle);
17-
assertEquals("4/4/19, 12:00\u202fAM", df_12_dt.format(midnight));
18-
assertEquals("4/4/19, 12:00\u202fPM", df_12_dt.format(noon));
17+
assertEquals("4/4/19, 12:00 AM", df_12_dt.format(midnight));
18+
assertEquals("4/4/19, 12:00 PM", df_12_dt.format(noon));
1919

2020
let df_23_dt = new Intl.DateTimeFormat(
2121
"en", {timeStyle: "short", dateStyle: "short", hourCycle: "h23"})

test/intl/date-format/format_range_hour_cycle.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,38 @@ let noon = new Date(2019, 3, 4, 12);
77
let df_11 = new Intl.DateTimeFormat(
88
"en", {hour: "numeric", minute: "numeric", hourCycle: "h11"})
99
assertEquals("h11", df_11.resolvedOptions().hourCycle);
10-
assertEquals("0:00\u202fAM", df_11.formatRange(midnight, midnight));
11-
assertEquals("0:00\u202fPM", df_11.formatRange(noon, noon));
10+
assertEquals("0:00 AM", df_11.formatRange(midnight, midnight));
11+
assertEquals("0:00 PM", df_11.formatRange(noon, noon));
1212

1313
let df_11_t = new Intl.DateTimeFormat(
1414
"en", {timeStyle: "short", hourCycle: "h11"})
1515
assertEquals("h11", df_11_t.resolvedOptions().hourCycle);
16-
assertEquals("0:00\u202fAM", df_11_t.formatRange(midnight, midnight));
17-
assertEquals("0:00\u202fPM", df_11_t.formatRange(noon, noon));
16+
assertEquals("0:00 AM", df_11_t.formatRange(midnight, midnight));
17+
assertEquals("0:00 PM", df_11_t.formatRange(noon, noon));
1818

1919
let df_11_dt = new Intl.DateTimeFormat(
2020
"en", {timeStyle: "short", dateStyle: "short", hourCycle: "h11"})
2121
assertEquals("h11", df_11_dt.resolvedOptions().hourCycle);
22-
assertEquals("4/4/19, 0:00\u202fAM", df_11_dt.formatRange(midnight, midnight));
23-
assertEquals("4/4/19, 0:00\u202fPM", df_11_dt.formatRange(noon, noon));
22+
assertEquals("4/4/19, 0:00 AM", df_11_dt.formatRange(midnight, midnight));
23+
assertEquals("4/4/19, 0:00 PM", df_11_dt.formatRange(noon, noon));
2424

2525
let df_12 = new Intl.DateTimeFormat(
2626
"en", {hour: "numeric", minute: "numeric", hourCycle: "h12"})
2727
assertEquals("h12", df_12.resolvedOptions().hourCycle);
28-
assertEquals("12:00\u202fAM", df_12.formatRange(midnight, midnight));
29-
assertEquals("12:00\u202fPM", df_12.formatRange(noon, noon));
28+
assertEquals("12:00 AM", df_12.formatRange(midnight, midnight));
29+
assertEquals("12:00 PM", df_12.formatRange(noon, noon));
3030

3131
let df_12_t = new Intl.DateTimeFormat(
3232
"en", {timeStyle: "short", hourCycle: "h12"})
3333
assertEquals("h12", df_12_t.resolvedOptions().hourCycle);
34-
assertEquals("12:00\u202fAM", df_12_t.formatRange(midnight, midnight));
35-
assertEquals("12:00\u202fPM", df_12_t.formatRange(noon, noon));
34+
assertEquals("12:00 AM", df_12_t.formatRange(midnight, midnight));
35+
assertEquals("12:00 PM", df_12_t.formatRange(noon, noon));
3636

3737
let df_12_dt = new Intl.DateTimeFormat(
3838
"en", {timeStyle: "short", dateStyle: "short", hourCycle: "h12"})
3939
assertEquals("h12", df_12_dt.resolvedOptions().hourCycle);
40-
assertEquals("4/4/19, 12:00\u202fAM", df_12_dt.formatRange(midnight, midnight));
41-
assertEquals("4/4/19, 12:00\u202fPM", df_12_dt.formatRange(noon, noon));
40+
assertEquals("4/4/19, 12:00 AM", df_12_dt.formatRange(midnight, midnight));
41+
assertEquals("4/4/19, 12:00 PM", df_12_dt.formatRange(noon, noon));
4242

4343
let df_23 = new Intl.DateTimeFormat(
4444
"en", {hour: "numeric", minute: "numeric", hourCycle: "h23"})

test/intl/date-format/hour_cycle.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ let noon = new Date(2019, 3, 4, 12);
77
let df_11 = new Intl.DateTimeFormat(
88
"en", {hour: "numeric", minute: "numeric", hourCycle: "h11"})
99
assertEquals("h11", df_11.resolvedOptions().hourCycle);
10-
assertEquals("0:00\u202fAM", df_11.format(midnight));
11-
assertEquals("0:00\u202fPM", df_11.format(noon));
10+
assertEquals("0:00 AM", df_11.format(midnight));
11+
assertEquals("0:00 PM", df_11.format(noon));
1212

1313
let df_12 = new Intl.DateTimeFormat(
1414
"en", {hour: "numeric", minute: "numeric", hourCycle: "h12"})
1515
assertEquals("h12", df_12.resolvedOptions().hourCycle);
16-
assertEquals("12:00\u202fAM", df_12.format(midnight));
17-
assertEquals("12:00\u202fPM", df_12.format(noon));
16+
assertEquals("12:00 AM", df_12.format(midnight));
17+
assertEquals("12:00 PM", df_12.format(noon));
1818

1919
let df_23 = new Intl.DateTimeFormat(
2020
"en", {hour: "numeric", minute: "numeric", hourCycle: "h23"})

test/intl/date-format/time_style_hour_cycle.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ let noon = new Date(2019, 3, 4, 12);
88
let df_11_t = new Intl.DateTimeFormat(
99
"en", {timeStyle: "short", hourCycle: "h11"})
1010
assertEquals("h11", df_11_t.resolvedOptions().hourCycle);
11-
assertEquals("0:00\u202fAM", df_11_t.format(midnight));
12-
assertEquals("0:00\u202fPM", df_11_t.format(noon));
11+
assertEquals("0:00 AM", df_11_t.format(midnight));
12+
assertEquals("0:00 PM", df_11_t.format(noon));
1313

1414
let df_12_t = new Intl.DateTimeFormat(
1515
"en", {timeStyle: "short", hourCycle: "h12"})
1616
assertEquals("h12", df_12_t.resolvedOptions().hourCycle);
17-
assertEquals("12:00\u202fAM", df_12_t.format(midnight));
18-
assertEquals("12:00\u202fPM", df_12_t.format(noon));
17+
assertEquals("12:00 AM", df_12_t.format(midnight));
18+
assertEquals("12:00 PM", df_12_t.format(noon));
1919

2020
let df_23_t = new Intl.DateTimeFormat(
2121
"en", {timeStyle: "short", hourCycle: "h23"})

test/intl/regress-1074578.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ const d1 = new Date("2020-05-25T00:00:00.000Z");
1818
const d2 = new Date("2020-05-31T00:00:00.000Z");
1919

2020
// Before tz2020a change will get "May 25, 2020 at 1:00:00 AM GMT+1"
21-
assertEquals("May 25, 2020 at 12:00:00\u202fAM GMT", df1.format(d1));
21+
assertEquals("May 25, 2020 at 12:00:00 AM GMT", df1.format(d1));
2222

2323
// Before tz2020a change will get "May 31, 2020 at 1:00:00 AM GMT+1"
24-
assertEquals("May 31, 2020 at 12:00:00\u202fAM GMT", df1.format(d2));
24+
assertEquals("May 31, 2020 at 12:00:00 AM GMT", df1.format(d2));
2525

2626
// B. Test Canada's Yukon advanced to -07 year-round on 2020-03-08.
2727
const df2 = new Intl.DateTimeFormat(
@@ -33,11 +33,11 @@ const d4 = new Date("2021-03-09T00:00Z");
3333
// Before tz2020a change will get "March 8, 2020 at 5:00:00 PM PDT"
3434
// In tz2020a it should be "March 8, 2020 at 5:00:00 PM MST"
3535
// but tz2020b roll this back.
36-
assertEquals("March 8, 2020 at 5:00:00\u202fPM PDT", df2.format(d3));
36+
assertEquals("March 8, 2020 at 5:00:00 PM PDT", df2.format(d3));
3737

3838
// Before tz2020a change will get "March 8, 2021 at 4:00:00 PM PST"
3939
// After tz2021a1 it now become "March 8, 2021 at 5:00:00 PM GMT-7".
40-
assertEquals("March 8, 2021 at 5:00:00\u202fPM GMT-7", df2.format(d4));
40+
assertEquals("March 8, 2021 at 5:00:00 PM GMT-7", df2.format(d4));
4141

4242
// C. Test America/Nuuk renamed from America/Godthab.
4343

test/intl/regress-527926.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ assertEquals("03:00", fmt.format(date));
1616

1717
fmt = new Intl.DateTimeFormat(
1818
'ru', {hour:'2-digit', minute: '2-digit', hour12: true});
19-
assertEquals("03:00\u202fAM", fmt.format(date));
19+
assertEquals("03:00 AM", fmt.format(date));

test/mjsunit/mjsunit.status

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,9 @@
475475

476476
# Non-BMP characters currently aren't considered identifiers in no_i18n
477477
'harmony/private-name-surrogate-pair': [PASS,FAIL],
478+
479+
# Tests ICU-specific behavior.
480+
'regress/regress-crbug-1414292': [SKIP],
478481
}], # 'no_i18n'
479482

480483
##############################################################################
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2023 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
const date = new Date("Wed Feb 15 2023 00:00:00 GMT+0100");
6+
const localeString = date.toLocaleString("en-US");
7+
// No narrow-width space should be found
8+
assertEquals(-1, localeString.search('\u202f'));
9+
// Regular space should match the character between time and AM/PM.
10+
assertMatches(/:\d\d:\d\d [AP]M$/, localeString);
11+
12+
const formatter = new Intl.DateTimeFormat('en', {timeStyle: "long"})
13+
const formattedString = formatter.format(date)
14+
// No narrow-width space should be found
15+
assertEquals(-1, formattedString.search('\u202f'));
16+
// Regular space should match the character between time and AM/PM.
17+
assertMatches(/:\d\d:\d\d [AP]M$/, localeString);

test/test262/test262.status

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,10 @@
10801080
'language/expressions/assignmenttargettype/direct-callexpression-arguments': [FAIL],
10811081
'language/expressions/assignmenttargettype/parenthesized-callexpression-arguments': [FAIL],
10821082

1083+
# We replace U+202F (narrow-width space) with U+0020 (regular space).
1084+
# https://crbug.com/1414292
1085+
'intl402/DateTimeFormat/prototype/format/timedatestyle-en': [FAIL],
1086+
10831087
############################ INVALID TESTS #############################
10841088

10851089
# Test makes unjustified assumptions about the number of calls to SortCompare.

0 commit comments

Comments
 (0)