timerender: Track browser time zone.

We add a variable `browser_time_zone` to track the same
separately from `display_time_zone`.

This is used to check whether the user profile time zone matches
the browser's time zone, as a part of #16957, and will later be
used in #16958.

We also add methods to check whether a given timezone is the same
as that of the browser, making use of the browser's own
canonicalization process.

Tests are added to ensure that the time zone comparison
logic works for timezones observing DST.

Fixes part of #16957
This commit is contained in:
Kislay Udbhav Verma
2024-08-17 18:15:16 +05:30
committed by Tim Abbott
parent a817671809
commit a2c6c11296
2 changed files with 98 additions and 1 deletions

View File

@@ -18,10 +18,14 @@ import * as util from "./util.ts";
let next_timerender_id = 0;
export let display_time_zone = new Intl.DateTimeFormat().resolvedOptions().timeZone;
export let display_time_zone = browser_time_zone();
const formatter_map = new Map<string, Intl.DateTimeFormat>();
export function browser_time_zone(): string {
return new Intl.DateTimeFormat().resolvedOptions().timeZone;
}
export function clear_for_testing(): void {
next_timerender_id = 0;
}
@@ -550,3 +554,19 @@ export function should_display_profile_incomplete_alert(timestamp: number): bool
}
return false;
}
export function browser_canonicalize_timezone(uncanonicalized_timezone: string): string {
try {
// we use the runtime's default locale, to match _browser_time_zone_.
const canonicalized_timezone = new Intl.DateTimeFormat(undefined, {
timeZone: uncanonicalized_timezone,
}).resolvedOptions().timeZone;
return canonicalized_timezone;
} catch {
return "";
}
}
export function is_browser_timezone_same_as(uncanonicalized_target_timezone: string): boolean {
return browser_time_zone() === browser_canonicalize_timezone(uncanonicalized_target_timezone);
}

View File

@@ -653,3 +653,80 @@ run_test("should_display_profile_incomplete_alert", () => {
assert.equal(timerender.should_display_profile_incomplete_alert(realm_date_created_secs), true);
});
run_test("canonicalize_time_zones", () => {
assert.equal(
timerender.browser_canonicalize_timezone("Asia/Calcutta"),
timerender.browser_canonicalize_timezone("Asia/Kolkata"),
);
assert.equal(
timerender.browser_canonicalize_timezone("Europe/Kiev"),
timerender.browser_canonicalize_timezone("Europe/Kyiv"),
);
assert.equal(timerender.browser_canonicalize_timezone("Invalid/Timezone"), "");
assert.equal(timerender.is_browser_timezone_same_as(timerender.browser_time_zone()), true);
// This just ensures that the function doesn't always return true
assert.equal(timerender.is_browser_timezone_same_as("Invalid/Timezone"), false);
function get_time_in_timezone(date, timezone) {
return Date.parse(date.toLocaleString("en-US", {timeZone: timezone}));
}
function get_offset_difference_at_date(tz1, tz2, reference_date) {
const date1 = get_time_in_timezone(reference_date, tz1);
const date2 = get_time_in_timezone(reference_date, tz2);
return date1 - date2;
}
// We should be able to tell timezones apart, even if they have the same offset.
// One of the two pairs below will have the same offset at any given time.
assert.notEqual(
timerender.browser_canonicalize_timezone("America/Phoenix"),
timerender.browser_canonicalize_timezone("America/Denver"),
);
assert.notEqual(
timerender.browser_canonicalize_timezone("America/Phoenix"),
timerender.browser_canonicalize_timezone("America/Los_Angeles"),
);
// The current time in America/Phoenix does equal the current time
// in one of the two other time zones
const now = new Date();
const now_phoenix = get_time_in_timezone(now, "America/Phoenix");
const now_denver = get_time_in_timezone(now, "America/Denver");
const now_la = get_time_in_timezone(now, "America/Los_Angeles");
// Both conditions cannot simultaneously be true since we know we can
// tell timezones apart and DST will not cease to be observed any time soon.
// So we can OR the two conditions.
assert.equal(now_denver === now_phoenix || now_la === now_phoenix, true);
const dst_date = new Date("Sat, 17 Jul 2024 11:05:12 GMT");
// The offset difference between America/Phoenix and America/Los_Angeles is 0
// when DST is in effect in America/Los_Angeles.
assert.equal(
get_offset_difference_at_date("America/Los_Angeles", "America/Phoenix", dst_date),
0,
);
// and similarly for Phoenix and Denver, the offset difference is -1 hour.
assert.equal(
get_offset_difference_at_date("America/Phoenix", "America/Denver", dst_date),
-3600000,
);
const non_dst_date = new Date("Sat, 17 Feb 2024 11:05:12 GMT");
// The offset difference between America/Phoenix and America/Los_Angeles is -1 hour
// when DST is not in effect in America/Los_Angeles.
assert.equal(
get_offset_difference_at_date("America/Los_Angeles", "America/Phoenix", non_dst_date),
-3600000,
);
// and similarly for Phoenix and Denver, the offset difference is 0.
assert.equal(
get_offset_difference_at_date("America/Phoenix", "America/Denver", non_dst_date),
0,
);
});