g1t/apps/sudo/app/lib/time.test.ts

42 lines2,891 bytesCodeBlame
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { localValue, utc } from "./incidents.ts";
5import { fromLocalInput, readZone, toLocalInput, when, zoneAbbr } from "./time.ts";
6
7const AT = new Date("2026-10-06T07:27:54.222Z");
8
9test("the zone: the staff member's choice, else Cloudflare's guess, else UTC", () => {
10 assert.deepEqual(readZone(null, "America/Los_Angeles"), { zone: "America/Los_Angeles", chosen: false });
11 assert.deepEqual(readZone("x=1; sudo_tz=Europe%2FBerlin", "America/Los_Angeles"), { zone: "Europe/Berlin", chosen: true });
12 assert.deepEqual(readZone("sudo_tz=Mars%2FOlympus", undefined), { zone: "UTC", chosen: false });
13 assert.deepEqual(readZone(undefined, 7), { zone: "UTC", chosen: false });
14});
15
16test("a time on a page: in the zone, with its abbreviation; UTC on hover", () => {
17 assert.deepEqual(when(AT, "America/Los_Angeles", true), { text: "Oct 6, 2026, 12:27 AM", zone: "PDT", utc: "Oct 6, 2026, 7:27 AM UTC" });
18 assert.deepEqual(when(AT, "UTC", true), { text: "Oct 6, 2026, 7:27 AM", zone: "UTC", utc: "Oct 6, 2026, 7:27 AM UTC" });
19 // A day without a time: the day in the zone, which can differ from UTC's.
20 assert.equal(when(new Date("2026-10-06T03:13:00Z"), "America/Los_Angeles", false).text, "Oct 5, 2026");
21 assert.equal(when(AT, "Not/AZone", true).zone, "UTC");
22 assert.equal(zoneAbbr(AT, "Europe/Berlin"), "CEST");
23 assert.equal(zoneAbbr(AT, "Asia/Tokyo"), "UTC+9");
24});
25
26test("form times are read and shown in the zone", () => {
27 assert.equal(fromLocalInput("2026-10-05T14:00", "America/Los_Angeles"), "2026-10-05T21:00:00.000Z");
28 assert.equal(fromLocalInput("2026-12-05T14:00", "America/Los_Angeles"), "2026-12-05T22:00:00.000Z", "standard time in winter");
29 assert.equal(fromLocalInput("2026-10-05T14:00", "Asia/Kolkata"), "2026-10-05T08:30:00.000Z");
30 assert.equal(fromLocalInput("2026-10-05T14:00"), "2026-10-05T14:00:00.000Z");
31 assert.equal(fromLocalInput("2026-10-05T14:00:00Z", "America/Los_Angeles"), "2026-10-05T14:00:00.000Z", "an explicit offset wins");
32 assert.equal(fromLocalInput("garbage", "America/Los_Angeles"), null);
33 assert.equal(toLocalInput("2026-10-05T21:00:00.000Z", "America/Los_Angeles"), "2026-10-05T14:00");
34 assert.equal(toLocalInput("2026-10-05T14:00:00.000Z"), "2026-10-05T14:00");
35 // The incidents forms' helpers go through the same.
36 assert.equal(utc("2026-10-05T14:00", "Europe/Berlin"), "2026-10-05T12:00:00.000Z");
37 assert.equal(localValue("2026-10-05T12:00:00.000Z", "Europe/Berlin"), "2026-10-05T14:00");
38 // Round trips either side of the clock changes in Berlin (an hour that happens twice in autumn is ambiguous, and read as the later one).
39 for (const at of ["2026-03-29T00:30:00.000Z", "2026-03-29T01:30:00.000Z", "2026-10-25T03:30:00.000Z"]) {
40 assert.equal(fromLocalInput(toLocalInput(at, "Europe/Berlin"), "Europe/Berlin"), at);
41 }
42});