format('Y-m-d') === $date; } /** * @return array{0: int, 1: int} */ public static function rangeBounds( string $range, string $date, string $customStart, string $customEnd, ?int $now = null ): array { if (!in_array($range, self::RANGES, true)) { throw new InvalidArgumentException('Unbekannter Zeitraum.'); } $now ??= time(); if ($range === 'total') { return [0, $now]; } if ($range === 'custom') { $start = self::date($customStart); $end = self::date($customEnd); if ($start > $end) { throw new InvalidArgumentException('Das Startdatum liegt nach dem Enddatum.'); } return [$start->getTimestamp(), $end->modify('+1 day')->getTimestamp()]; } $base = self::date($date); switch ($range) { case 'day': $start = $base; $end = $start->modify('+1 day'); break; case 'week': $start = $base->modify('monday this week'); $end = $start->modify('+1 week'); break; case 'month': $start = $base->modify('first day of this month'); $end = $start->modify('first day of next month'); break; case 'year': $start = $base->setDate((int) $base->format('Y'), 1, 1); $end = $start->modify('+1 year'); break; default: throw new InvalidArgumentException('Unbekannter Zeitraum.'); } return [$start->getTimestamp(), $end->getTimestamp()]; } /** * @return array{ * Produktion: float, * Einspeisung: float, * Netzbezug: float, * Hausverbrauch: float, * Eigenverbrauch: float, * Eigenverbrauchsquote: float, * Autarkiegrad: float * } */ public static function metrics( float $production, float $feedIn, float $grid, ?float $consumption = null ): array { $production = max(0.0, $production); $feedIn = max(0.0, $feedIn); $grid = max(0.0, $grid); $house = $consumption === null ? max(0.0, $production - $feedIn + $grid) : max(0.0, $consumption); $selfConsumption = min($production, max(0.0, $house - $grid)); return [ 'Produktion' => $production, 'Einspeisung' => $feedIn, 'Netzbezug' => $grid, 'Hausverbrauch' => $house, 'Eigenverbrauch' => $selfConsumption, 'Eigenverbrauchsquote' => $production > 0.0 ? min(100.0, ($selfConsumption / $production) * 100.0) : 0.0, 'Autarkiegrad' => $house > 0.0 ? min(100.0, ($selfConsumption / $house) * 100.0) : 0.0, ]; } public static function normalizeColor(string $color, string $fallback): string { $color = trim($color); if (preg_match('/^#[0-9A-Fa-f]{6}$/', $color) === 1) { return strtoupper($color); } if (preg_match('/^[0-9]+$/', $color) === 1) { $legacyColor = (int) $color; if ($legacyColor >= 0 && $legacyColor <= 0xFFFFFF) { return sprintf('#%06X', $legacyColor); } } return strtoupper($fallback); } private static function date(string $date): DateTimeImmutable { if (!self::isValidDate($date)) { throw new InvalidArgumentException('Ungültiges Datum.'); } return new DateTimeImmutable($date . ' 00:00:00', new DateTimeZone(date_default_timezone_get())); } }