mirror of https://github.com/zulip/zulip.git
time_zone_util: Avoid relying on timeZoneName: "longOffset".
Safari doesn’t support it yet. Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
3eb5b20c41
commit
07bd1f28d1
|
@ -1,30 +1,41 @@
|
|||
import assert from "minimalistic-assert";
|
||||
const parsable_formats = new Map<string, Intl.DateTimeFormat>();
|
||||
|
||||
const offset_formats = new Map<string, Intl.DateTimeFormat>();
|
||||
|
||||
function get_offset_format(time_zone: string): Intl.DateTimeFormat {
|
||||
let format = offset_formats.get(time_zone);
|
||||
function get_parsable_format(time_zone: string): Intl.DateTimeFormat {
|
||||
let format = parsable_formats.get(time_zone);
|
||||
if (format === undefined) {
|
||||
format = new Intl.DateTimeFormat("en-US", {
|
||||
timeZoneName: "longOffset",
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
second: "numeric",
|
||||
hourCycle: "h23",
|
||||
timeZone: time_zone,
|
||||
});
|
||||
offset_formats.set(time_zone, format);
|
||||
parsable_formats.set(time_zone, format);
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
/** Get the given time zone's offset in milliseconds at the given date. */
|
||||
export function get_offset(date: number | Date, time_zone: string): number {
|
||||
const offset_string = get_offset_format(time_zone)
|
||||
.formatToParts(date)
|
||||
.find((part) => part.type === "timeZoneName")!.value;
|
||||
if (offset_string === "GMT") {
|
||||
return 0;
|
||||
}
|
||||
const m = /^GMT(([+-])\d\d):(\d\d)$/.exec(offset_string);
|
||||
assert(m !== null, offset_string);
|
||||
return (Number(m[1]) * 60 + Number(m[2] + m[3])) * 60000;
|
||||
const parts = Object.fromEntries(
|
||||
get_parsable_format(time_zone)
|
||||
.formatToParts(date)
|
||||
.map((part) => [part.type, part.value]),
|
||||
);
|
||||
return (
|
||||
Date.UTC(
|
||||
Number(parts.year),
|
||||
Number(parts.month) - 1,
|
||||
Number(parts.day),
|
||||
Number(parts.hour),
|
||||
Number(parts.minute),
|
||||
Number(parts.second),
|
||||
) -
|
||||
(Number(date) - (Number(date) % 1000))
|
||||
);
|
||||
}
|
||||
|
||||
/** Get the start of the day for the given date in the given time zone. */
|
||||
|
|
|
@ -23,6 +23,7 @@ const chatham_dst_begin = new Date("2022-09-24T14:00Z");
|
|||
const chatham_dst_end = new Date("2023-04-01T14:00Z");
|
||||
const kiritimati = "Pacific/Kiritimati";
|
||||
const kiritimati_date_skip = new Date("1994-12-31T10:00Z");
|
||||
const fractional_date = new Date("2023-01-02T03:04:05.678Z");
|
||||
|
||||
run_test("get_offset", () => {
|
||||
assert.equal(get_offset(ny_new_year, "UTC"), 0);
|
||||
|
@ -37,6 +38,9 @@ run_test("get_offset", () => {
|
|||
assert.equal(get_offset(chatham_dst_end, chatham), (12 * 60 + 45) * 60000);
|
||||
assert.equal(get_offset(pre(kiritimati_date_skip), kiritimati), -10 * 60 * 60000);
|
||||
assert.equal(get_offset(kiritimati_date_skip, kiritimati), 14 * 60 * 60000);
|
||||
assert.equal(get_offset(fractional_date, "UTC"), 0);
|
||||
assert.equal(get_offset(fractional_date, ny), -5 * 60 * 60000);
|
||||
assert.equal(get_offset(fractional_date, kiritimati), 14 * 60 * 60000);
|
||||
});
|
||||
|
||||
run_test("start_of_day", () => {
|
||||
|
|
Loading…
Reference in New Issue