From f11df655a272898e29265c6ce99de9837b43eea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 21 May 2026 19:22:18 +0200 Subject: [PATCH] refactor(tz): export toBerlinYmd and dedup two more BERLIN_DAY_FORMATTER sites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit W4-ARCH-HYGIENE's 7-way dedup landed in `src/lib/tz/resolver.ts` but left two more BERLIN_DAY_FORMATTER declarations alive: - `src/lib/insights/bucket-series.ts` needed the numeric `{year, month, day}` parts for `Date.UTC` arithmetic, so it kept its own formatter and a local `toBerlinYmd` helper. - `src/lib/analytics/bp-in-target.ts` used a separate en-CA formatter to skip the part-reassembly when producing the YYYY-MM-DD string. Export a sibling `toBerlinYmd(date)` helper from the resolver that returns the formatter's raw string parts so `bucket-series.ts` can parse them into numbers without instantiating a second formatter. Switch `bp-in-target.ts` to the existing `toBerlinDayKey` import — the en-CA shortcut is a microscopic speedup not worth the duplicate formatter and the divergent contract. Net: one shared formatter for every Berlin-anchored cache key in the tree. The 272 insights / analytics / tz unit tests still pass. --- src/lib/analytics/bp-in-target.ts | 12 +----------- src/lib/insights/bucket-series.ts | 21 +++++++-------------- src/lib/tz/resolver.ts | 17 ++++++++++++++++- 3 files changed, 24 insertions(+), 26 deletions(-) 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;