Skip to content

Commit a79c6a1

Browse files
committed
Polyfill: Adjust time zone transition search window
For a few time zones, the two-week search window for an interval to bisect is too large, because transitions occur less than two weeks apart. Special-case these time zones. This allows increasing the default window to 19 days (a bunch of Argentinian time zones have transitions less than 20 days apart, so this seems like a good boundary where we don't have to add too many special cases.) This gives a small performance improvement in the common case. UPSTREAM_COMMIT=da53e9acead66c3616971e487236bde1a731c564
1 parent 2c8b319 commit a79c6a1

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

lib/ecmascript.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2737,6 +2737,31 @@ export function GetNamedTimeZoneDateTimeParts(id: string, epochNanoseconds: JSBI
27372737
return BalanceISODateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond);
27382738
}
27392739

2740+
// Most time zones never transition twice within a short span of days. We still
2741+
// accommodate twitchy zones, albeit at a performance penalty. 19 days is the
2742+
// default window, past which we'd need to start adding many more special cases.
2743+
function searchWindowForTransitions(id: string) {
2744+
if (id === 'Africa/El_Aaiun') return DAY_MS * 17;
2745+
if (id === 'America/Argentina/Tucuman') return DAY_MS * 12;
2746+
if (id === 'Europe/Tirane') return DAY_MS * 11;
2747+
if (id === 'Europe/Riga') return DAY_MS * 10;
2748+
if (id === 'Europe/Simferopol' || id === 'Europe/Vienna') return DAY_MS * 9;
2749+
if (id === 'Africa/Tunis') return DAY_MS * 8;
2750+
if (
2751+
id === 'America/Boa_Vista' ||
2752+
id === 'America/Fortaleza' ||
2753+
id === 'America/Maceio' ||
2754+
id === 'America/Noronha' ||
2755+
id === 'America/Recife' ||
2756+
id === 'Asia/Gaza' || // dubious, only in future calculations
2757+
id === 'Asia/Hebron' || // ditto
2758+
id === 'Brazil/DeNoronha'
2759+
) {
2760+
return DAY_MS * 6;
2761+
}
2762+
return DAY_MS * 19;
2763+
}
2764+
27402765
export function GetNamedTimeZoneNextTransition(id: string, epochNanoseconds: JSBI): JSBI | null {
27412766
if (id === 'UTC') return null; // UTC fast path
27422767

@@ -2759,8 +2784,9 @@ export function GetNamedTimeZoneNextTransition(id: string, epochNanoseconds: JSB
27592784
let leftOffsetNs = GetNamedTimeZoneOffsetNanosecondsImpl(id, leftMs);
27602785
let rightMs = leftMs;
27612786
let rightOffsetNs = leftOffsetNs;
2787+
const searchWindow = searchWindowForTransitions(id);
27622788
while (leftOffsetNs === rightOffsetNs && leftMs < uppercap) {
2763-
rightMs = leftMs + DAY_MS * 2 * 7;
2789+
rightMs = leftMs + searchWindow;
27642790
if (rightMs > MS_MAX) return null;
27652791
rightOffsetNs = GetNamedTimeZoneOffsetNanosecondsImpl(id, rightMs);
27662792
if (leftOffsetNs === rightOffsetNs) {
@@ -2817,8 +2843,9 @@ export function GetNamedTimeZonePreviousTransition(id: string, epochNanoseconds:
28172843
let rightOffsetNs = GetNamedTimeZoneOffsetNanosecondsImpl(id, rightMs);
28182844
let leftMs = rightMs;
28192845
let leftOffsetNs = rightOffsetNs;
2846+
const searchWindow = searchWindowForTransitions(id);
28202847
while (rightOffsetNs === leftOffsetNs && rightMs > BEFORE_FIRST_DST) {
2821-
leftMs = rightMs - DAY_MS * 2 * 7;
2848+
leftMs = rightMs - searchWindow;
28222849
if (leftMs < BEFORE_FIRST_DST) return null;
28232850
leftOffsetNs = GetNamedTimeZoneOffsetNanosecondsImpl(id, leftMs);
28242851
if (rightOffsetNs === leftOffsetNs) {

0 commit comments

Comments
 (0)