format('d.m.Y H:i') : $date; } else { $dt = DateTime::createFromFormat('Ymd', $date); return $dt ? $dt->format('d.m.Y') : $date; } } function format_ics_date_with_timezone($date, $timezone = null) { // Unterstützt sowohl ganztägige als auch Zeitangaben if (strpos($date, 'T') !== false) { $dt = null; // Prüfe ob es eine UTC-Zeit ist (endet mit Z) if (substr($date, -1) === 'Z') { // UTC-Zeit: 20250405T130000Z $utc_date = substr($date, 0, -1); // Entferne das Z $dt = DateTime::createFromFormat('Ymd\THis', $utc_date, new DateTimeZone('UTC')); } elseif ($timezone) { // Zeitzone angegeben: 20250405T130000 mit TZID try { $dt = new DateTime($date, new DateTimeZone($timezone)); } catch (Exception $e) { // Fallback auf lokale Zeit $dt = DateTime::createFromFormat('Ymd\THis', substr($date, 0, 15)); } } else { // Lokale Zeit ohne Zeitzone $dt = DateTime::createFromFormat('Ymd\THis', substr($date, 0, 15)); } if ($dt) { // ISO 8601 Format für JavaScript $iso_date = $dt->format('Y-m-d\TH:i:sP'); // P = Zeitzone $display_date = $dt->format('d.m.Y H:i'); return [ 'iso' => $iso_date, 'display' => $display_date, 'has_time' => true, ]; } return [ 'iso' => $date, 'display' => $date, 'has_time' => true, ]; } else { $dt = DateTime::createFromFormat('Ymd', $date); if ($dt) { $iso_date = $dt->format('Y-m-d'); $display_date = $dt->format('d.m.Y'); return [ 'iso' => $iso_date, 'display' => $display_date, 'has_time' => false, ]; } return [ 'iso' => $date, 'display' => $date, 'has_time' => false, ]; } } // ICS-Datei laden $ics = @file_get_contents(CAL_URL); if (!$ics) { echo '
Kalender konnte nicht geladen werden.
'; return; } // Termine parsen function parse_ics($ics) { $lines = explode("\n", $ics); $events = []; $event = []; $inEvent = false; foreach ($lines as $line) { $line = trim($line); if ($line === 'BEGIN:VEVENT') { $inEvent = true; $event = []; } elseif ($line === 'END:VEVENT') { $inEvent = false; $events[] = $event; } elseif ($inEvent) { // Property kann Parameter enthalten, z.B. DTSTART;TZID=Europe/Berlin:20240701T19000000 $parts = explode(':', $line, 2); if (count($parts) === 2) { $key = $parts[0]; $val = $parts[1]; // Zeitzoneninformation extrahieren $timezone = null; if (preg_match('/TZID=([^:;]+)/', $key, $matches)) { $timezone = $matches[1]; } // Nur den eigentlichen Property-Namen extrahieren $cleanKey = strtoupper(preg_replace('/;.+$/', '', $key)); $event[$cleanKey] = $val; // Zeitzoneninformation separat speichern if ($timezone && in_array($cleanKey, ['DTSTART', 'DTEND'])) { $event[$cleanKey . '_TZID'] = $timezone; } } } } return $events; } $events = parse_ics($ics); return function () use ($events) { return $events; };