Start the time zone transition search before the first transition in 1844 - #372
Closed
craig-o-curtis wants to merge 1 commit into
Closed
craig-o-curtis wants to merge 1 commit into
craig-o-curtis wants to merge 1 commit into
Conversation
…1844
GetNamedTimeZoneNextTransition() jumps forward to BEFORE_FIRST_DST
(1847-01-01) and GetNamedTimeZonePreviousTransition() stops there,
because 1847 was taken to be the year of the first transition in the
TZDB. It no longer is: Asia/Manila, Pacific/Guam, Pacific/Saipan,
Pacific/Kosrae and Pacific/Palau change sides of the date line on
1844-12-31, skipping that local day. Those transitions were not found:
Temporal.Instant.from('1800-01-01T00:00:00Z')
.toZonedDateTimeISO('Asia/Manila')
.getTimeZoneTransition('next');
// 1899-09-06T12:00:00+08:00[Asia/Manila]
// (expected 1845-01-01T00:00:00+08:04[Asia/Manila])
GetStartOfDay() uses this function for the skipped day, so
Temporal.PlainDate.from('1844-12-31').toZonedDateTime('Asia/Manila')
also gave the 1899 transition, and hoursInDay on 1844-12-30 was
479340.06444444443 instead of 24.
Move the constant to 1844-01-01. That is almost a year before the first
transition, as 1847-01-01 was before Europe/London's on 1847-12-01, so
the early return in GetNamedTimeZonePreviousTransition() still can't
cut off a search window (19 days at most).
Also present in tc39/proposal-temporal; reported as
tc39/proposal-temporal#3330.
This was referenced Sep 19, 2026
Contributor
|
Ditto, will apply it in proposal-temporal and pull it in later. Thanks 😄 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is not a port: the fix isn't in tc39/proposal-temporal yet. The same bug is there, and I reported it as tc39/proposal-temporal#3330 with the same change, so a later sync can pick it up. It doesn't depend on #367–#371 or #361. It touches the same file as #371 but a different part of it, and the two apply together cleanly.
What was wrong
GetNamedTimeZoneNextTransition()jumps forward toBEFORE_FIRST_DST(1847-01-01) andGetNamedTimeZonePreviousTransition()stops there, because 1847 was taken to be the year of the first transition in the TZDB (e70d632). It no longer is. Five zones change sides of the date line on 1844-12-31 and skip that local day: Asia/Manila (-15:56→+08:04), Pacific/Guam and Pacific/Saipan (-14:21→+09:39), Pacific/Kosrae (-13:08→+10:52) and Pacific/Palau (-15:02→+08:58). Onmain(production build):mainTemporal.Instant.from('1800-01-01T00:00:00Z').toZonedDateTimeISO('Asia/Manila').getTimeZoneTransition('next')1899-09-06T12:00:00+08:00[Asia/Manila]1845-01-01T00:00:00+08:04[Asia/Manila]Temporal.Instant.from('1846-06-01T00:00:00Z').toZonedDateTimeISO('Asia/Manila').getTimeZoneTransition('previous')null1845-01-01T00:00:00+08:04[Asia/Manila]Temporal.PlainDate.from('1844-12-31').toZonedDateTime('Asia/Manila')1899-09-06T12:00:00+08:00[Asia/Manila]1845-01-01T00:00:00+08:04[Asia/Manila]Temporal.ZonedDateTime.from('1844-12-30T12:00[Asia/Manila]').hoursInDay479340.0644444444324Temporal.ZonedDateTime.from('1844-12-30T12:00[Asia/Manila]').round({ smallestUnit: 'day' })1844-12-30T00:00:00-15:56[Asia/Manila]1845-01-01T00:00:00+08:04[Asia/Manila]Temporal.Instant.from('1800-01-01T00:00:00Z').toZonedDateTimeISO('Europe/London').getTimeZoneTransition('next')1847-12-01T00:01:15+00:00[Europe/London]The expected values are Chrome 153's native Temporal. The same calls in Guam, Saipan, Kosrae and Palau are wrong in the same way, with their 1901 transition in place of Manila's 1899 one. The offsets themselves were right, because they come from
Intl.DateTimeFormat. Local 1844-12-31 doesn't exist in these zones, soGetStartOfDay()searches for the next transition after the day before. That search jumped to 1847 and found the next transition after it. Development builds give the same results.What this changes
BEFORE_FIRST_DSTmoves to 1844-01-01, with a comment saying where the first transition is (lib/ecmascript.ts, one line plus a comment). That is almost a year before the first transition, as 1847-01-01 was before Europe/London's on 1847-12-01. So the earlyreturn nullinGetNamedTimeZonePreviousTransition()still can't cut off a search window, which is 19 days at most. The only cost is up to three more years of 19-day steps when a search reaches the constant. Antarctica/Troll is the worst case (first transition in 2005):previousfrom just before that transition took 4.2–4.3 ms both before and after the change.Not fixed by this PR
getTimeZoneTransition('previous')from 1844-12-31T00:00Z isnullin all 418 zones, so there is none today.Testing
Node 24.21.0 (ICU 78.3, tzdata 2026c): jest 607 passed; eslint, prettier and
tscheckclean. test262 at the pinned version: intl402/Temporal 330 passed and 8 expected failures, built-ins/Temporal 4330 passed.I compared these rows with Chrome 153:
mainnextfrom 1800,previousfrom 1846, 1848, 1900 and from 1 ns after the transition;toZonedDateTime,hoursInDayandstartOfDayon 1844-12-29 … 1845-01-02; the skipped day with eachdisambiguation;add/subtract/round/untilacross it; controls in Europe/London and America/New_York, and 2026 lookups (157 rows)Intl.supportedValuesOf('timeZone'): first transition after 1800,previousfrom 1 ns after it, from 1845-06-01 and from 1850-01-01 (1,672 rows)Every row outside the five zones (1,652 zone-scan rows and 20 controls) is byte-identical with and without this PR. So are
nextandpreviousfrom the first of every month of 2020–2030 in 24 zones (6,336 lookups). With #371 applied as well, all 1,829 rows still match Chrome 153.I made the same change in tc39/proposal-temporal at e8cc03fc97 and got the same results there.