import { RangeKey, Every } from '@/types/strom'; // 'raw' = 1-Sekunden-Rohdaten (measurement vzlogger) — aktuell, fuer 24h // 'rollup' = stuendliche Snapshots (measurement arbeit_hourly) — schnell, fuer 7d/31d/365d export type Source = 'raw' | 'rollup'; export interface ResolvedRange { start: Date; // Beginn des sichtbaren Zeitraums (inklusiv) stop: Date; // Ende des sichtbaren Zeitraums (exklusiv) every: Every; // Fensterbreite je Balken source: Source; } const HOUR_MS = 60 * 60 * 1000; const DAY_MS = 24 * HOUR_MS; /** * Berechnet start/stop/every fuer ein Diagramm aus den Query-Parametern. * * - 24h: ohne date -> rollierend die letzten 24h ab jetzt (1 Balken/Stunde) * mit date -> dieser Kalendertag 00:00-24:00 * - 7d: 7 Tage endend am gewaehlten Tag (Default heute), 1 Balken/Stunde * - 31d: aktueller Monat (Default) -> rollierend die letzten 31 Tage endend heute; * ein konkret gewaehlter (vergangener) Monat -> dieser Kalendermonat. 1 Balken/Tag * - 365d: komplettes gewaehltes Jahr (Default aktuelles Jahr), 1 Balken/Tag */ export function resolveRange( range: RangeKey, params: { date?: string | null; month?: string | null; year?: string | null } ): ResolvedRange { const now = new Date(); switch (range) { case '24h': { if (params.date) { const start = startOfDay(params.date); return { start, stop: new Date(start.getTime() + DAY_MS), every: '1h', source: 'raw' }; } // rollierend: letzte 24h ab jetzt (Rohdaten = aktuellster Wert) return { start: new Date(now.getTime() - 24 * HOUR_MS), stop: now, every: '1h', source: 'raw' }; } case '7d': { // Ende = Ende des gewaehlten Tages (Default heute) const day = params.date ? startOfDay(params.date) : startOfDay(toDateString(now)); const stop = new Date(day.getTime() + DAY_MS); return { start: new Date(stop.getTime() - 7 * DAY_MS), stop, every: '1h', source: 'rollup' }; } case '31d': { const { year, month } = params.month ? parseMonth(params.month) : { year: now.getFullYear(), month: now.getMonth() }; // Default/laufender Monat: rollierend die letzten 31 Tage endend heute // (analog zu 24h). Tagesgrenzen lokal via Datums-Arithmetik -> DST-sicher. if (year === now.getFullYear() && month === now.getMonth()) { const stop = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1); // Beginn morgen const start = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1 - 31); return { start, stop, every: '1d', source: 'rollup' }; } // Konkret gewaehlter (vergangener) Monat: kompletter Kalendermonat const start = new Date(year, month, 1); const stop = new Date(year, month + 1, 1); return { start, stop, every: '1d', source: 'rollup' }; } case '365d': { // ein Balken pro Monat const year = params.year ? parseInt(params.year, 10) : now.getFullYear(); const start = new Date(year, 0, 1); const stop = new Date(year + 1, 0, 1); return { start, stop, every: '1mo', source: 'rollup' }; } } } function startOfDay(dateStr: string): Date { const [y, m, d] = dateStr.split('-').map(Number); return new Date(y, m - 1, d); } function parseMonth(monthStr: string): { year: number; month: number } { const [y, m] = monthStr.split('-').map(Number); return { year: y, month: m - 1 }; } function toDateString(d: Date): string { const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); return `${y}-${m}-${day}`; } // Ein Fenster vor `d` (fuer den difference-Vorlauf). Monate kalendergenau. export function windowStartBefore(d: Date, every: Every): Date { const r = new Date(d); if (every === '1h') r.setTime(r.getTime() - HOUR_MS); else if (every === '1d') r.setTime(r.getTime() - DAY_MS); else r.setMonth(r.getMonth() - 1); // '1mo' return r; }