diff --git a/src/lib/analytics/bp-in-target.ts b/src/lib/analytics/bp-in-target.ts index 134c50b8f..bfbdde9dc 100644 --- a/src/lib/analytics/bp-in-target.ts +++ b/src/lib/analytics/bp-in-target.ts @@ -60,17 +60,7 @@ export interface BpReading { const SYS_HYPOTENSION_FLOOR = 90; const DIA_HYPOTENSION_FLOOR = 50; -const BERLIN_DAY_FORMATTER = new Intl.DateTimeFormat("en-CA", { - timeZone: "Europe/Berlin", - year: "numeric", - month: "2-digit", - day: "2-digit", -}); - -function toBerlinDayKey(date: Date): string { - // en-CA gives us the YYYY-MM-DD shape directly. - return BERLIN_DAY_FORMATTER.format(date); -} +import { toBerlinDayKey } from "@/lib/tz/resolver"; /** * Pair a systolic reading with its closest diastolic by absolute time diff --git a/src/lib/insights/bucket-series.ts b/src/lib/insights/bucket-series.ts index f9922e7e9..29744f89b 100644 --- a/src/lib/insights/bucket-series.ts +++ b/src/lib/insights/bucket-series.ts @@ -16,12 +16,7 @@ * does not produce 360 zero-rows of noise. */ -const BERLIN_DAY_FORMATTER = new Intl.DateTimeFormat("en-US", { - timeZone: "Europe/Berlin", - year: "numeric", - month: "2-digit", - day: "2-digit", -}); +import { toBerlinYmd as toBerlinYmdStrings } from "@/lib/tz/resolver"; const MS_PER_DAY = 24 * 60 * 60 * 1000; @@ -65,14 +60,12 @@ interface BerlinYmd { } function toBerlinYmd(date: Date): BerlinYmd { - const parts = BERLIN_DAY_FORMATTER.formatToParts(date); - const year = Number(parts.find((p) => p.type === "year")?.value); - const month = Number(parts.find((p) => p.type === "month")?.value); - const day = Number(parts.find((p) => p.type === "day")?.value); - if (!year || !month || !day) { - throw new Error("Could not derive Berlin Y-M-D"); - } - return { year, month, day }; + const parts = toBerlinYmdStrings(date); + return { + year: Number(parts.year), + month: Number(parts.month), + day: Number(parts.day), + }; } /** UTC midnight of the Berlin calendar day containing `date`. */ diff --git a/src/lib/tz/resolver.ts b/src/lib/tz/resolver.ts index f8899a015..e3191f4e6 100644 --- a/src/lib/tz/resolver.ts +++ b/src/lib/tz/resolver.ts @@ -74,6 +74,21 @@ const BERLIN_DAY_FORMATTER = new Intl.DateTimeFormat("en-US", { * stored zone. */ export function toBerlinDayKey(date: Date): string { + const { year, month, day } = toBerlinYmd(date); + return `${year}-${month}-${day}`; +} + +/** + * Same formatter, but returns the numeric `{year, month, day}` parts + * instead of the reassembled string. Used by `bucket-series.ts` for + * `Date.UTC(year, month - 1, day)` arithmetic where parsing the string + * back would be wasted work. + */ +export function toBerlinYmd(date: Date): { + year: string; + month: string; + day: string; +} { const parts = BERLIN_DAY_FORMATTER.formatToParts(date); const year = parts.find((part) => part.type === "year")?.value; const month = parts.find((part) => part.type === "month")?.value; @@ -83,7 +98,7 @@ export function toBerlinDayKey(date: Date): string { throw new Error("Could not derive Berlin day key"); } - return `${year}-${month}-${day}`; + return { year, month, day }; } const TTL_MS = 60_000;