Skip to content
38 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { knownTimeZone, localTime, timeZoneLabel, timeZoneNames, utcOffset } from "./time-zone.ts";
5
6// 2026-10-08 21:42 UTC: 3:42 PM in Denver (MDT), the next morning in Tokyo.
7const NOW = Date.UTC(2026, 9, 8, 21, 42);
8
9test("a profile's local time is the time of day in its zone", () => {
10 // ICU puts a narrow no-break space before AM/PM in some versions.
11 const at = (zone: string) => localTime(zone, NOW, "en-US")?.replace(/\s/gu, " ");
12 assert.equal(at("America/Denver"), "3:42 PM");
13 assert.equal(at("Asia/Tokyo"), "6:42 AM");
14 assert.equal(at("UTC"), "9:42 PM");
15});
16
17test("no zone, or one the runtime does not know, shows no time", () => {
18 assert.equal(localTime(null, NOW, "en-US"), null);
19 assert.equal(localTime("", NOW, "en-US"), null);
20 assert.equal(localTime("Mars/Olympus_Mons", NOW, "en-US"), null);
21 assert.ok(!knownTimeZone("Mars/Olympus_Mons"));
22 assert.ok(knownTimeZone("Europe/Berlin"));
23});
24
25test("the zones to pick from are sorted, with UTC and a saved one always there", () => {
26 const names = timeZoneNames("Mars/Olympus_Mons");
27 assert.ok(names.includes("UTC"));
28 assert.ok(names.includes("America/Denver"));
29 assert.ok(names.includes("Mars/Olympus_Mons"));
30 assert.deepEqual(names, [...names].sort((a, b) => a.localeCompare(b)));
31});
32
33test("zones read as places, with their offset", () => {
34 assert.equal(timeZoneLabel("America/Port_of_Spain"), "America/Port of Spain");
35 assert.equal(utcOffset("America/Denver", NOW), "UTC−06:00");
36 assert.equal(utcOffset("Asia/Kolkata", NOW), "UTC+05:30");
37 assert.equal(utcOffset("UTC", NOW), "UTC+00:00");
38});