Skip to content

Intl.DateTimeFormat formatToParts aborts the process (unreachable code) when the locale pattern has Y: please cherry-pick V8 0426b0d1045d into v22.x, v24.x and v26.x #67076

Open

Description

@craig-o-curtis

Version

v26.12.1 (V8 14.6.202.34-node.40, ICU 78.3, CLDR 48.0).
Also v24.21.0 (V8 13.6.233.17-node.53) and v22.22.2 (V8 12.4.254.21-node.39).

Platform

Darwin 27.0.0 arm64. The crash is in platform-independent code.

Subsystem

intl, deps/v8

What steps will reproduce the bug?

node -e "new Intl.DateTimeFormat('gd', { year: 'numeric', month: 'short', timeZone: 'UTC' }).formatToParts(0)"
echo $?   # 133

This one matches V8's regression test (test/intl/date-format/year-woy-field.js):

node -e "new Intl.DateTimeFormat('te-u-ca-buddhist', { year: 'numeric', month: 'long' }).formatToParts(0)"

formatRangeToParts aborts in the same way. Here formatToParts works and only the range call aborts:

node -e "const f = new Intl.DateTimeFormat('ak-u-ca-buddhist', { year: 'numeric', month: 'short', timeZone: 'UTC' }); f.formatToParts(0); f.formatRangeToParts(0, 5e9)"

format() and formatRange() do not abort with the same options.

How often does it reproduce? Is there a required condition?

Every time. The condition is a locale whose ICU date pattern for the requested options contains
the pattern letter Y (week-based year). try/catch does not help, because V8 ends the process.

What is the expected behavior? Why is that the expected behavior?

formatToParts returns an array of parts and does not end the process.

ECMA-402 2026, §11.5.5 FormatDateTimePattern,
handles a pattern field it does not recognise in its last step: "Let unknown be an
implementation-, locale-, and numbering system-dependent String based on epochNanoseconds and p.
Append the Record { [[Type]]: "unknown", [[Value]]: unknown } to result." So even an
unrecognised field yields a part, never an abort.

What do you see instead?

The process exits with SIGTRAP (exit status 133):

#
# Fatal error in , line 0
# unreachable code
#
#FailureMessage Object: 0x16d2c8a78
----- Native stack trace -----

 1: node::NodePlatform::GetStackTracePrinter()::$_0::__invoke()
 2: V8_Fatal(char const*, ...)
 3: v8::base::LazyInstanceImpl<v8::internal::(anonymous namespace)::SpecialTimeZoneMap, ...>::InitInstance(void*)

Frame 3 is mis-symbolised. The UNREACHABLE() is the default: case of
IcuDateFieldIdToDateType in deps/v8/src/objects/js-date-time-format.cc, which has no case for
ICU's UDAT_YEAR_WOY_FIELD (the Y field).

Additional information

V8 has fixed it. V8 commit 0426b0d1045d, "[intl] Handle UDAT_YEAR_WOY_FIELD in
IcuDateFieldIdToDateType" (https://chromium-review.googlesource.com/c/v8/v8/+/8320131, bug
https://issues.chromium.org/issues/553923523), changes src/objects/js-date-time-format.cc:

  • IcuDateFieldIdToDateType returns year for UDAT_YEAR_WOY_FIELD.
  • The year PatternItem also accepts "YY" (2-digit) and "Y" (numeric).

It adds test/intl/date-format/year-woy-field.js. Node.js main (V8 15.6.75) already has the fix.

Each release branch:

Branch V8 case UDAT_YEAR_WOY_FIELD Year PatternItem
main 15.6.75 present has "YY" and "Y"
v26.x 14.6.202 missing same shape as the patch (DateTimeProperty::kYear)
v24.x 13.6.233 missing older shape: PatternItem(Year::kShift, "year", {{"yy", "2-digit"}, {"y", "numeric"}}, ...)
v22.x 12.4.254 missing older shape, as in v24.x

The one-line case stops the abort on its own. On v24.x and v22.x the "YY"/"Y" entries
would go into the older PatternItem call by hand. The
V8 maintenance guide
says fixes for abandoned V8 branches are cherry-picked in this repository.

What the fix does not change. After the fix these locales still print a week-based year
where a calendar year is meant: gd formats 30 December 2024 as Dùbh 2025. That is CLDR data,
not Node.js or V8. CLDR-19873 (https://unicode-org.atlassian.net/browse/CLDR-19873) reports the
same data defect for gl and kek.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions