Skip to content

Commit da53e9a

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. Closes: #3110
1 parent ea29a30 commit da53e9a

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

polyfill/lib/ecmascript.mjs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2391,6 +2391,31 @@ export function GetNamedTimeZoneDateTimeParts(id, epochNanoseconds) {
23912391
return BalanceISODateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond);
23922392
}
23932393

2394+
// Most time zones never transition twice within a short span of days. We still
2395+
// accommodate twitchy zones, albeit at a performance penalty. 19 days is the
2396+
// default window, past which we'd need to start adding many more special cases.
2397+
function searchWindowForTransitions(id) {
2398+
if (id === 'Africa/El_Aaiun') return DAY_MS * 17;
2399+
if (id === 'America/Argentina/Tucuman') return DAY_MS * 12;
2400+
if (id === 'Europe/Tirane') return DAY_MS * 11;
2401+
if (id === 'Europe/Riga') return DAY_MS * 10;
2402+
if (id === 'Europe/Simferopol' || id === 'Europe/Vienna') return DAY_MS * 9;
2403+
if (id === 'Africa/Tunis') return DAY_MS * 8;
2404+
if (
2405+
id === 'America/Boa_Vista' ||
2406+
id === 'America/Fortaleza' ||
2407+
id === 'America/Maceio' ||
2408+
id === 'America/Noronha' ||
2409+
id === 'America/Recife' ||
2410+
id === 'Asia/Gaza' || // dubious, only in future calculations
2411+
id === 'Asia/Hebron' || // ditto
2412+
id === 'Brazil/DeNoronha'
2413+
) {
2414+
return DAY_MS * 6;
2415+
}
2416+
return DAY_MS * 19;
2417+
}
2418+
23942419
export function GetNamedTimeZoneNextTransition(id, epochNanoseconds) {
23952420
if (id === 'UTC') return null; // UTC fast path
23962421

@@ -2413,8 +2438,9 @@ export function GetNamedTimeZoneNextTransition(id, epochNanoseconds) {
24132438
let leftOffsetNs = GetNamedTimeZoneOffsetNanosecondsImpl(id, leftMs);
24142439
let rightMs = leftMs;
24152440
let rightOffsetNs = leftOffsetNs;
2441+
const searchWindow = searchWindowForTransitions(id);
24162442
while (leftOffsetNs === rightOffsetNs && leftMs < uppercap) {
2417-
rightMs = leftMs + DAY_MS * 2 * 7;
2443+
rightMs = leftMs + searchWindow;
24182444
if (rightMs > MS_MAX) return null;
24192445
rightOffsetNs = GetNamedTimeZoneOffsetNanosecondsImpl(id, rightMs);
24202446
if (leftOffsetNs === rightOffsetNs) {
@@ -2471,8 +2497,9 @@ export function GetNamedTimeZonePreviousTransition(id, epochNanoseconds) {
24712497
let rightOffsetNs = GetNamedTimeZoneOffsetNanosecondsImpl(id, rightMs);
24722498
let leftMs = rightMs;
24732499
let leftOffsetNs = rightOffsetNs;
2500+
const searchWindow = searchWindowForTransitions(id);
24742501
while (rightOffsetNs === leftOffsetNs && rightMs > BEFORE_FIRST_DST) {
2475-
leftMs = rightMs - DAY_MS * 2 * 7;
2502+
leftMs = rightMs - searchWindow;
24762503
if (leftMs < BEFORE_FIRST_DST) return null;
24772504
leftOffsetNs = GetNamedTimeZoneOffsetNanosecondsImpl(id, leftMs);
24782505
if (rightOffsetNs === leftOffsetNs) {

0 commit comments

Comments
 (0)