Skip to content

Polyfill: Update Meiji era start date - #368

Closed
craig-o-curtis wants to merge 2 commits into
js-temporal:mainfrom
craig-o-curtis:port-meiji-era-start
Closed

craig-o-curtis wants to merge 2 commits into
js-temporal:mainfrom
craig-o-curtis:port-meiji-era-start

Conversation

@craig-o-curtis

@craig-o-curtis craig-o-curtis commented Sep 18, 2026 •

Copy link
Copy Markdown

Ports two tc39/proposal-temporal commits, one commit each:

What was wrong

On main, the Japanese calendar starts the Meiji era on 1868-09-08, and gives every date from then to the end of 1872 the era meiji:

Temporal.PlainDate.from('1870-03-01').withCalendar('japanese');  // meiji 3
Temporal.PlainDate.from('1872-12-31').withCalendar('japanese');  // meiji 5
Temporal.PlainDate.from({ calendar: 'japanese', era: 'ce', eraYear: 1870, month: 3, day: 1 });  // meiji 3

The spec, as changed by tc39/proposal-intl-era-monthcode#102, says that dates up to and including 1872-12-31 use the same years and eras as gregory, and that ISO year 1873, when Japan switched to the Gregorian calendar, is year 6 of Meiji. So all three calls above should give ce 1870 or ce 1872.

What this changes

  • First commit: moves the Meiji era start from 1868-09-08 to 1868-10-23. 1868-09-08 was the date in the Japanese lunisolar calendar, taken as if it were a Gregorian date. The Gregorian date is 1868-10-23 (CLDR-11375).
  • Second commit: replaces the internal hasYearZero era flag with startingYear, so that the Meiji era can start at year 6, on 1873-01-01. Dates before that use ce or bce, so the three calls above now give ce 1870, ce 1872 and ce 1870. Input using era: 'meiji' with eraYear 1 to 5 still works and gives the matching ce date. For example, { era: 'meiji', eraYear: 5, month: 12, day: 31 } is 1872-12-31, ce 1872. Dates from 1873-01-01 on are unchanged: 1873-01-01 is still meiji 6.

Not fixed by this PR

These behave the same on main and on this branch:

  • toLocaleString() still shows the ICU era. Temporal.PlainDate.from('1872-12-31').withCalendar('japanese').toLocaleString('en-u-ca-japanese', { era: 'short', year: 'numeric', month: 'numeric', day: 'numeric' }) gives 12/31/5 Meiji, although .era is now ce. Formatting goes through Intl.DateTimeFormat, which uses ICU's era data, not the polyfill's.
  • 13 other Japanese calendar tests in newer test262 fail, none of them about the Meiji era: adding or subtracting a year from a leap day with overflow: 'reject' should throw but doesn't (6 files, */prototype/{add,subtract}/leap-year-japanese.js), a missing eraYear throws RangeError instead of TypeError (6 files, calendarresolvefields-error-ordering-japanese.js), and PlainMonthDay/from/japanese-month-codes.js (1 file, wrong reference year). April 2026 rebase, part 3 #361 fixes all 13 (see Testing).

Testing

Node 24.21.0 (ICU 78.3, CLDR 48): jest passes (607 tests), and test262 at the pinned version passes with no new failures or unexpected passes (intl402/Temporal 330 passed, 8 expected failures; built-ins/Temporal 4330 passed).

Our pinned test262 has no Japanese era tests. So I ran the 125 intl402/Temporal/**/*japanese*.js tests by hand: 124 at test262 3c6180f, the commit that tc39/proposal-temporal#3263 pinned, plus PlainDate/from/japanese-pre-meiji.js, which test262 added later:

Build Failing (of 125)
main 18
#361 alone 5
this PR 13
this PR with #361 applied on top 0

The 5 tests this PR fixes are {PlainDate,PlainDateTime,PlainYearMonth,ZonedDateTime}/from/era-boundary-japanese.js and PlainDate/from/japanese-pre-meiji.js. The 13 still failing are the ones listed under "Not fixed by this PR". This PR applies cleanly on top of #361.

Differences from upstream (TypeScript)

  • lib/calendar.ts has separate InputEra and Era types where upstream has one JSDoc typedef. startingYear is optional in InputEra and required in Era, so HelperBase's placeholder anchorEra (for calendars without eras) sets startingYear: 1.
  • Upstream's new comment "we count years prior to 1872 as CE" is ported word for word. It should say 1873, because all of 1872 is CE (see the spec text above).

This was based on erroneous data in CLDR.
See https://unicode-org.atlassian.net/browse/CLDR-11375

UPSTREAM_COMMIT=977d11e0d0a47896cb43124c57b6364058e017a8
Update internal era data to change hasYearZero to startingYear, so that
we can accommodate the starting year of 6.

NOTE: (this info below wasn't in the upstream commit)
This implements the normative change in
tc39/proposal-intl-era-monthcode#102, from tc39/proposal-temporal#3263.
In the Japanese calendar, dates up to and including 1872-12-31 now use
the "ce" and "bce" eras, as in the gregory calendar, and the Meiji era
starts at year 6 on 1873-01-01. For example,
Temporal.PlainDate.from('1872-12-31').withCalendar('japanese') was
meiji 5 and is now ce 1872. Dates from 1873-01-01 on are unchanged.

Still the same after this commit: toLocaleString() formats through
Intl.DateTimeFormat, which still shows 1872-12-31 as 5 Meiji.

TypeScript port: the Era type requires startingYear, so HelperBase's
placeholder anchorEra sets startingYear: 1. The ported comment "we
count years prior to 1872 as CE" should say 1873, since all of 1872 is
CE; it is kept word for word here.

UPSTREAM_COMMIT=993e6322d56971b68e539d007a32c62bf94a4032
@ptomato

ptomato commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Thanks for proactively porting this, but I'd prefer to keep the commits ported in order — otherwise the rebases become unmanageable. I apologize that it's been taking a while.

@ptomato ptomato closed this Sep 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants