Skip to content

Commit

Permalink
Fix broken caching in guessOffsetForZone
Browse files Browse the repository at this point in the history
  • Loading branch information
diesieben07 committed Feb 13, 2025
1 parent aedc7bd commit 20139a3
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 7 deletions.
22 changes: 16 additions & 6 deletions src/datetime.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,15 +389,25 @@ function normalizeUnitWithLocalWeeks(unit) {
// This is safe for quickDT (used by local() and utc()) because we don't fill in
// higher-order units from tsNow (as we do in fromObject, this requires that
// offset is calculated from tsNow).
/**
* @param {Zone} zone
* @return {number}
*/
function guessOffsetForZone(zone) {
if (!zoneOffsetGuessCache[zone]) {
if (zoneOffsetTs === undefined) {
zoneOffsetTs = Settings.now();
}
if (zoneOffsetTs === undefined) {
zoneOffsetTs = Settings.now();
}

zoneOffsetGuessCache[zone] = zone.offset(zoneOffsetTs);
// Do not cache anything but IANA zones, because it is not safe to do so.
// Guessing an offset which is not present in the zone can cause wrong results from fixOffset
if (zone.type !== "iana") {
return zone.offset(zoneOffsetTs);
}
const zoneName = zone.name;
if (!zoneOffsetGuessCache[zoneName]) {
zoneOffsetGuessCache[zoneName] = zone.offset(zoneOffsetTs);
}
return zoneOffsetGuessCache[zone];
return zoneOffsetGuessCache[zoneName];
}

// this is a dumbed down version of fromObject() that runs about 60% faster
Expand Down
24 changes: 23 additions & 1 deletion test/datetime/create.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* global test expect */

import { DateTime } from "../../src/luxon";
import { DateTime, Settings } from "../../src/luxon";
import Helpers from "../helpers";

const withDefaultLocale = Helpers.withDefaultLocale,
Expand Down Expand Up @@ -897,3 +897,25 @@ test("private language subtags don't break unicode subtags", () => {
expect(res.outputCalendar).toBe("islamic");
expect(res.numberingSystem).toBe("thai");
});

test("DateTime.local works even after time zone change", () => {
// This test catches errors produced when guessOffsetForZone produces wildy wrong guesses
// This guards against a regression by broken caching in that method
Settings.resetCaches();
withDefaultZone("America/Los_Angeles", () => {
expect(DateTime.local(2024).year).toBe(2024);
});
withDefaultZone("America/Chicago", () => {
const dateTime = DateTime.local(2024, 11, 3, 0, 5, 0);
expect(dateTime.zoneName).toBe("America/Chicago");
expect(dateTime.toObject()).toEqual({
year: 2024,
month: 11,
day: 3,
hour: 0,
minute: 5,
second: 0,
millisecond: 0,
});
});
});

0 comments on commit 20139a3

Please sign in to comment.