// SPDX-FileCopyrightText: 2026 Paul Schoeneck // // SPDX-License-Identifier: AGPL-3.0-only AND LicenseRef-KIBU-Additional-Terms export function localClock(now = new Date()) { const parts = new Intl.DateTimeFormat("en-GB", { timeZone: process.env.APP_TIMEZONE ?? "Europe/Berlin", year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", hourCycle: "h23", }).formatToParts(now); const get = (type: Intl.DateTimeFormatPartTypes) => parts.find((p) => p.type === type)!.value; const day = `${get("year")}-${get("month")}-${get("day")}`; const weekday = new Date(`${day}T12:00:00Z`).getUTCDay() || 7; return { day, time: `${get("hour")}:${get("minute")}`, weekday }; } export function pickupState(pickup: string | null, time: string, end?: string | null) { if (!pickup) return "none"; const minutes = (value: string) => Number(value.slice(0, 2)) * 60 + Number(value.slice(3, 5)); const delta = minutes(pickup) - minutes(time); if (minutes(end ?? pickup) < minutes(time)) return "overdue"; if (delta <= 15) return "due"; return "later"; } export function displayDay(day: string) { return new Intl.DateTimeFormat("de-DE", { weekday: "long", day: "numeric", month: "long", timeZone: "UTC", }).format(new Date(`${day}T12:00:00Z`)); } export function timeInZone(instant: string, timeZone: string) { return new Intl.DateTimeFormat("en-GB", { timeZone, hour: "2-digit", minute: "2-digit", hourCycle: "h23" }) .format(new Date(instant)); } export function localInstant(day: string, time: string, timeZone: string): Date { const wall = Date.parse(`${day}T${time}:00Z`); const format = (date: Date) => new Intl.DateTimeFormat("sv-SE", { timeZone, year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", hourCycle: "h23", }).format(date).replace(" ", "T"); const offsets = new Set([-36, 0, 36].map((hours) => { const sample = new Date(wall + hours * 3_600_000); return Date.parse(`${format(sample)}Z`) - sample.getTime(); })); const candidates = [...offsets].map((offset) => new Date(wall - offset)) .filter((date) => format(date) === `${day}T${time}:00`); if (candidates.length !== 1) { throw new Error("Diese Uhrzeit ist wegen der Zeitumstellung nicht eindeutig oder existiert nicht. Bitte eine andere Uhrzeit wählen."); } return candidates[0]; }