diff --git a/site/collections/termine.php b/site/collections/termine.php index 1b60e3f..6e7e3e3 100644 --- a/site/collections/termine.php +++ b/site/collections/termine.php @@ -1,66 +1,142 @@ -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)); - - return $dt ? $dt->format('d.m.Y H:i') : $date; + } } else { - $dt = DateTime::createFromFormat('Ymd', $date); - - return $dt ? $dt->format('d.m.Y') : $date; + // 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.
'; +if (!$ics) { + echo '
Kalender konnte nicht geladen werden.
'; - return; + 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]; - // Nur den eigentlichen Property-Namen extrahieren - $key = strtoupper(preg_replace('/;.+$/', '', $key)); - $event[$key] = $val; - } - } - } + $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]; - return $events; + // 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; + return $events; }; + diff --git a/site/snippets/home-termine.php b/site/snippets/home-termine.php index 5cd7c96..e734ec6 100644 --- a/site/snippets/home-termine.php +++ b/site/snippets/home-termine.php @@ -1,34 +1,34 @@ format('Ymd'); +// Aktuelles Datum +$today = new DateTime()->format('Ymd'); - // Nur zukünftige Termine anzeigen - $future_events = array_filter($events, function ($event) use ($today) { - return isset($event['DTSTART']) && $event['DTSTART'] >= $today; - }); +// Nur zukünftige Termine anzeigen +$future_events = array_filter($events, function ($event) use ($today) { + return isset($event['DTSTART']) && $event['DTSTART'] >= $today; +}); - // Termine nach DTSTART in aufsteigender Reihenfolge sortieren - usort($future_events, function ($a, $b) { - return $a['DTSTART'] <=> $b['DTSTART']; - }); +// Termine nach DTSTART in aufsteigender Reihenfolge sortieren +usort($future_events, function ($a, $b) { + return $a['DTSTART'] <=> $b['DTSTART']; +}); - // --- Deutsche Monatsnamen --- - $de_months = [ - '01' => 'Jan', - '02' => 'Feb', - '03' => 'Mrz', - '04' => 'Apr', - '05' => 'Mai', - '06' => 'Jun', - '07' => 'Jul', - '08' => 'Aug', - '09' => 'Sep', - '10' => 'Okt', - '11' => 'Nov', - '12' => 'Dez', - ]; +// --- Deutsche Monatsnamen --- +$de_months = [ + '01' => 'Jan', + '02' => 'Feb', + '03' => 'Mrz', + '04' => 'Apr', + '05' => 'Mai', + '06' => 'Jun', + '07' => 'Jul', + '08' => 'Aug', + '09' => 'Sep', + '10' => 'Okt', + '11' => 'Nov', + '12' => 'Dez', +]; ?>
@@ -43,16 +43,19 @@
+ $desc = $event['DESCRIPTION'] ?? ''; + $timezone = $event['DTSTART_TZID'] ?? null; + $date_info = format_ics_date_with_timezone($start, $timezone); + $date = $date_info['display']; + $time = $date_info['has_time'] ? substr($date, 11) : 'ganztägig'; + $day = substr($date, 0, 2); + $month = substr($date, 3, 2); + $iso_date = $date_info['iso']; + ?>
@@ -66,7 +69,9 @@
-
+
@@ -81,8 +86,16 @@
-

-

ab Uhr

+

+

+ + ab Uhr + + ganztägig + +

@@ -169,6 +182,45 @@ // Initialer Aufruf updateArrowState(); + // Zeitzonenkonvertierung für lokale Zeiten + function convertTimesToLocal() { + const timeElements = document.querySelectorAll('.local-time'); + timeElements.forEach(element => { + const isoDate = element.getAttribute('data-iso-date'); + if (isoDate) { + try { + // Erstelle ein Date-Objekt aus der ISO-Date + // JavaScript erkennt automatisch UTC-Zeiten (mit Z oder +00:00) + const date = new Date(isoDate); + + // Prüfe ob das Datum gültig ist + if (isNaN(date.getTime())) { + console.warn('Ungültiges Datum:', isoDate); + return; + } + + // Formatiere die Zeit in der lokalen Zeitzone des Browsers + const localTime = date.toLocaleTimeString('de-DE', { + hour: '2-digit', + minute: '2-digit', + hour12: false + }); + + // Aktualisiere den Text + element.textContent = localTime; + + // Debug-Information (kann später entfernt werden) + console.log('Konvertiert:', isoDate, '->', localTime, 'in Zeitzone:', Intl.DateTimeFormat().resolvedOptions().timeZone); + } catch (error) { + console.warn('Fehler bei der Zeitzonenkonvertierung:', error, 'für Datum:', isoDate); + } + } + }); + } + + // Zeitzonenkonvertierung beim Laden der Seite + convertTimesToLocal(); + // Responsives Verhalten - bei Fenstergröße-Änderung window.addEventListener('resize', () => { // Anzahl der Karten je nach Bildschirmgröße anpassen diff --git a/site/snippets/termine.php b/site/snippets/termine.php index 7274264..f5e9cb3 100644 --- a/site/snippets/termine.php +++ b/site/snippets/termine.php @@ -4,77 +4,77 @@ $events = collection('termine'); // Nur Events mit DTSTART berücksichtigen $events = array_filter($events, function ($event) { - return isset($event['DTSTART']) && ! empty($event['DTSTART']); + return isset($event['DTSTART']) && !empty($event['DTSTART']); }); // Nach Datum sortieren usort($events, function ($a, $b) { - return strcmp($a['DTSTART'], $b['DTSTART']); + return strcmp($a['DTSTART'], $b['DTSTART']); }); // Aktuelles Datum -$today = (new DateTime())->format('Ymd'); +$today = new DateTime()->format('Ymd'); // Nur zukünftige Termine anzeigen $future_events = array_filter($events, function ($event) use ($today) { - return isset($event['DTSTART']) && $event['DTSTART'] >= $today; + return isset($event['DTSTART']) && $event['DTSTART'] >= $today; }); // --- Deutsche Monatsnamen --- $de_months = [ - '01' => 'Januar', - '02' => 'Februar', - '03' => 'März', - '04' => 'April', - '05' => 'Mai', - '06' => 'Juni', - '07' => 'Juli', - '08' => 'August', - '09' => 'September', - '10' => 'Oktober', - '11' => 'November', - '12' => 'Dezember', + '01' => 'Januar', + '02' => 'Februar', + '03' => 'März', + '04' => 'April', + '05' => 'Mai', + '06' => 'Juni', + '07' => 'Juli', + '08' => 'August', + '09' => 'September', + '10' => 'Oktober', + '11' => 'November', + '12' => 'Dezember', ]; // --- Gruppierung aller Termine nach Jahr und Monat für die Sidebar --- function group_events_by_year_month($events) { - $grouped = []; - foreach ($events as $event) { - if ( ! isset($event['DTSTART'])) { - continue; - } - $date = $event['DTSTART']; - $year = substr($date, 0, 4); - $month = substr($date, 4, 2); - $grouped[$year][$month][] = $event; - } - krsort($grouped); // Jahre absteigend - foreach ($grouped as &$months) { - krsort($months); // Monate absteigend + $grouped = []; + foreach ($events as $event) { + if (!isset($event['DTSTART'])) { + continue; } + $date = $event['DTSTART']; + $year = substr($date, 0, 4); + $month = substr($date, 4, 2); + $grouped[$year][$month][] = $event; + } + krsort($grouped); // Jahre absteigend + foreach ($grouped as &$months) { + krsort($months); // Monate absteigend + } - return $grouped; + return $grouped; } $all_events_grouped = group_events_by_year_month($events); // --- Filter aus URL --- -$filter_jahr = $_GET['jahr'] ?? null; +$filter_jahr = $_GET['jahr'] ?? null; $filter_monat = $_GET['monat'] ?? null; if ($filter_jahr && $filter_monat) { - $filtered_events = array_filter($events, function ($event) use ($filter_jahr, $filter_monat) { - $date = $event['DTSTART'] ?? ''; + $filtered_events = array_filter($events, function ($event) use ($filter_jahr, $filter_monat) { + $date = $event['DTSTART'] ?? ''; - return substr($date, 0, 4) === $filter_jahr && substr($date, 4, 2) === $filter_monat; - }); + return substr($date, 0, 4) === $filter_jahr && substr($date, 4, 2) === $filter_monat; + }); } elseif ($filter_jahr) { - $filtered_events = array_filter($events, function ($event) use ($filter_jahr) { - $date = $event['DTSTART'] ?? ''; + $filtered_events = array_filter($events, function ($event) use ($filter_jahr) { + $date = $event['DTSTART'] ?? ''; - return substr($date, 0, 4) === $filter_jahr; - }); + return substr($date, 0, 4) === $filter_jahr; + }); } else { - $filtered_events = $future_events; + $filtered_events = $future_events; } ?> @@ -85,54 +85,43 @@ if ($filter_jahr && $filter_monat) {

Termine nach Jahr/Monat

\ No newline at end of file