diff --git a/public/index.php b/public/index.php
index 7bd0dd9..858fdfb 100644
--- a/public/index.php
+++ b/public/index.php
@@ -31,6 +31,94 @@ if (!function_exists('formatDurationHoursMinutes')) {
return sprintf('%d Minuten', $restMinutes);
}
}
+if (!function_exists('eventDateTime')) {
+ function eventDateTime(array $event): ?DateTimeImmutable
+ {
+ if (empty($event['found']) || empty($event['local_iso'])) {
+ return null;
+ }
+
+ try {
+ return new DateTimeImmutable((string)$event['local_iso']);
+ } catch (Exception) {
+ return null;
+ }
+ }
+}
+if (!function_exists('intervalOverlapSeconds')) {
+ function intervalOverlapSeconds(?DateTimeImmutable $aStart, ?DateTimeImmutable $aEnd, ?DateTimeImmutable $bStart, ?DateTimeImmutable $bEnd): int
+ {
+ if ($aStart === null || $aEnd === null || $bStart === null || $bEnd === null) {
+ return 0;
+ }
+
+ $start = max($aStart->getTimestamp(), $bStart->getTimestamp());
+ $end = min($aEnd->getTimestamp(), $bEnd->getTimestamp());
+
+ return max(0, $end - $start);
+ }
+}
+if (!function_exists('planetVisibleIntervalsForDay')) {
+ function planetVisibleIntervalsForDay(array $planet, DateTimeImmutable $dayStart, DateTimeImmutable $dayEnd): array
+ {
+ $rise = eventDateTime($planet['rise'] ?? []);
+ $set = eventDateTime($planet['set'] ?? []);
+
+ if ($rise && $set) {
+ if ($rise <= $set) {
+ return [[$rise, $set]];
+ }
+
+ return [
+ [$dayStart, $set],
+ [$rise, $dayEnd],
+ ];
+ }
+
+ if ($rise) {
+ return [[$rise, $dayEnd]];
+ }
+
+ if ($set) {
+ return [[$dayStart, $set]];
+ }
+
+ return [];
+ }
+}
+if (!function_exists('planetVisibilityClass')) {
+ function planetVisibilityClass(array $planet, DateTimeImmutable $dayStart, DateTimeImmutable $dayEnd, array $ev, array $evNext): array
+ {
+ $intervals = planetVisibleIntervalsForDay($planet, $dayStart, $dayEnd);
+ if ($intervals === []) {
+ return ['class' => 'planet-visibility-bad', 'label' => 'am Tag'];
+ }
+
+ $astroDusk = eventDateTime($ev['astro_dusk'] ?? []);
+ $astroDawnNext = eventDateTime($evNext['astro_dawn'] ?? []);
+ $civilDusk = eventDateTime($ev['civil_dusk'] ?? []);
+ $civilDawnNext = eventDateTime($evNext['civil_dawn'] ?? []);
+
+ $nightSeconds = 0;
+ $twilightSeconds = 0;
+
+ foreach ($intervals as [$from, $to]) {
+ $nightSeconds += intervalOverlapSeconds($from, $to, $astroDusk, $astroDawnNext);
+ $twilightSeconds += intervalOverlapSeconds($from, $to, $civilDusk, $astroDusk);
+ $twilightSeconds += intervalOverlapSeconds($from, $to, $astroDawnNext, $civilDawnNext);
+ }
+
+ if ($nightSeconds > 0) {
+ return ['class' => 'planet-visibility-good', 'label' => 'nachts gut'];
+ }
+
+ if ($twilightSeconds > 0) {
+ return ['class' => 'planet-visibility-warn', 'label' => 'in der Daemmerung'];
+ }
+
+ return ['class' => 'planet-visibility-bad', 'label' => 'am Tag'];
+ }
+}
function idx_tleChecksum(string $line): int
{
@@ -281,6 +369,35 @@ if ($loggedIn) {
}
?>
+
@@ -310,6 +427,8 @@ if ($loggedIn) {
modify('+1 day');
$deepSkyStart = (!empty($ev['astro_dusk']['found']) && !empty($ev['astro_dusk']['local_iso']))
? new DateTimeImmutable($ev['astro_dusk']['local_iso'])
: null;
@@ -348,7 +467,8 @@ if ($loggedIn) {
- = h($planet['name']) ?>
+
+ = h($planet['name']) ?>
↑ = ($planet['rise']['found'] ?? false) ? h($planet['rise']['local_time']) : '—' ?>
↓ = ($planet['set']['found'] ?? false) ? h($planet['set']['local_time']) : '—' ?>