From 3631703e9f7b042632000ee98df3424787124c2b Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Wed, 29 Jul 2026 11:55:31 +0000 Subject: [PATCH] Bump WebKit: omit dayPeriod from resolvedOptions for bare 12-hour patterns Picks up oven-sh/WebKit#373. Any Intl.DateTimeFormat that resolves to a 12-hour cycle (hour with h11/h12, hour12: true, or a 12-hour locale default) was reporting resolvedOptions().dayPeriod === "short" even though no dayPeriod option was passed and the output contains no flexible day period. Feeding resolvedOptions() back into the constructor then requests dayPeriod for real, so the round-trip changes "10:05 AM" to "10:05 in the morning". setFormatsFromPattern in JSC was mapping the AM/PM pattern field 'a' into m_dayPeriod alongside the real flexible-day-period fields 'b'/'B'; 'a' is now left to hourCycle/hour12. formatToParts is unaffected. --- scripts/build/deps/webkit.ts | 2 +- test/js/web/intl/intl.test.ts | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/scripts/build/deps/webkit.ts b/scripts/build/deps/webkit.ts index 45502005f29a..92f4e2f415ac 100644 --- a/scripts/build/deps/webkit.ts +++ b/scripts/build/deps/webkit.ts @@ -3,7 +3,7 @@ * for local mode. Override via `--webkit-version=` to test a branch. * From https://github.com/oven-sh/WebKit releases. */ -export const WEBKIT_VERSION = "34c01d13391e00c06862a3d2c5b7fff350ac87e0"; +export const WEBKIT_VERSION = "autobuild-preview-pr-373-0c1a9be2"; /** * WebKit (JavaScriptCore) — the JS engine. diff --git a/test/js/web/intl/intl.test.ts b/test/js/web/intl/intl.test.ts index 86dc3758a8e8..aeb81fdbac31 100644 --- a/test/js/web/intl/intl.test.ts +++ b/test/js/web/intl/intl.test.ts @@ -86,6 +86,43 @@ describe("Intl.NumberFormat", () => { // --------------------------------------------------------------------------- describe("Intl.DateTimeFormat", () => { + test("resolvedOptions() omits dayPeriod for a bare 12-hour pattern", () => { + // The AM/PM marker ('a' in the ICU pattern) is governed by hourCycle/hour12, + // not the dayPeriod option. A 12-hour formatter that never asked for dayPeriod + // must not report one, and round-tripping resolvedOptions() must reproduce the + // same output. https://tc39.es/ecma402/#sec-initializedatetimeformat + const t = Date.UTC(2026, 0, 1, 10, 5); + const opts = { timeZone: "UTC", hour: "numeric", minute: "2-digit" } as const; + const a = new Intl.DateTimeFormat("en-US", opts); + const ro = a.resolvedOptions(); + const b = new Intl.DateTimeFormat("en-US", ro); + expect({ + dayPeriod: ro.dayPeriod, + hourCycle: ro.hourCycle, + original: a.format(t), + roundTrip: b.format(t), + }).toEqual({ + dayPeriod: undefined, + hourCycle: "h12", + original: "10:05 AM", + roundTrip: "10:05 AM", + }); + + expect( + new Intl.DateTimeFormat("en-US", { timeZone: "UTC", hour: "2-digit", hourCycle: "h11" }).resolvedOptions() + .dayPeriod, + ).toBeUndefined(); + + // When dayPeriod *is* requested it must still be reported. + expect( + new Intl.DateTimeFormat("en-US", { timeZone: "UTC", hour: "numeric", dayPeriod: "long" }).resolvedOptions() + .dayPeriod, + ).toBe("long"); + + // formatToParts still labels the AM/PM marker as type "dayPeriod" (ECMA-402 Table 16). + expect(a.formatToParts(t).find(p => p.value === "AM")?.type).toBe("dayPeriod"); + }); + snapshotIf("default", () => { const out: Record = {}; for (const loc of LOCALES) out[loc] = new Intl.DateTimeFormat(loc, { timeZone: "UTC" }).format(0);