Files
drivetimeplaner/backup/fahrschultermin_20260518_223313/www/fahrschultermin.de/app/Services/HolidayService.php

110 lines
4.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services;
use DateInterval;
use DateTimeImmutable;
use DateTimeZone;
final class HolidayService
{
private const STATES_WITH_EPIPHANY = ['BW', 'BY', 'ST'];
private const STATES_WITH_WOMENS_DAY = ['BE', 'MV'];
private const STATES_WITH_CORPUS_CHRISTI = ['BW', 'BY', 'HE', 'NW', 'RP', 'SL'];
private const STATES_WITH_ASSUMPTION = ['BY', 'SL'];
private const STATES_WITH_REFORMATION = ['BB', 'HB', 'HH', 'MV', 'NI', 'SN', 'ST', 'SH', 'TH'];
private const STATES_WITH_ALL_SAINTS = ['BW', 'BY', 'NW', 'RP', 'SL'];
private const STATES_WITH_REPENTANCE = ['SN'];
public function forRange(array $tenant, string $from, string $to): array
{
$timezone = new DateTimeZone((string) ($tenant['timezone'] ?? 'Europe/Berlin'));
$state = strtoupper((string) ($tenant['federal_state'] ?? 'BE'));
$start = (new DateTimeImmutable($from, new DateTimeZone('UTC')))->setTimezone($timezone)->setTime(0, 0);
$end = (new DateTimeImmutable($to, new DateTimeZone('UTC')))->setTimezone($timezone)->setTime(0, 0);
$years = [];
$day = $start;
while ($day <= $end) {
$years[(int) $day->format('Y')] = true;
$day = $day->add(new DateInterval('P1D'));
}
$holidaysByDate = [];
foreach (array_keys($years) as $year) {
foreach ($this->holidaysForYear((int) $year, $state, $timezone) as $date => $name) {
$holidaysByDate[$date] = $name;
}
}
$result = [];
$day = $start;
while ($day < $end) {
$key = $day->format('Y-m-d');
$result[$key] = [
'isSunday' => (int) $day->format('N') === 7,
'holidayName' => $holidaysByDate[$key] ?? null,
];
$day = $day->add(new DateInterval('P1D'));
}
return $result;
}
private function holidaysForYear(int $year, string $state, DateTimeZone $timezone): array
{
$easter = (new DateTimeImmutable('@' . (string) easter_date($year)))->setTimezone($timezone)->setTime(0, 0);
$holidays = [
$this->dateKey($year, 1, 1, $timezone) => 'Neujahr',
$easter->sub(new DateInterval('P2D'))->format('Y-m-d') => 'Karfreitag',
$easter->add(new DateInterval('P1D'))->format('Y-m-d') => 'Ostermontag',
$this->dateKey($year, 5, 1, $timezone) => 'Tag der Arbeit',
$easter->add(new DateInterval('P39D'))->format('Y-m-d') => 'Christi Himmelfahrt',
$easter->add(new DateInterval('P50D'))->format('Y-m-d') => 'Pfingstmontag',
$this->dateKey($year, 10, 3, $timezone) => 'Tag der Deutschen Einheit',
$this->dateKey($year, 12, 25, $timezone) => '1. Weihnachtstag',
$this->dateKey($year, 12, 26, $timezone) => '2. Weihnachtstag',
];
if (in_array($state, self::STATES_WITH_EPIPHANY, true)) {
$holidays[$this->dateKey($year, 1, 6, $timezone)] = 'Heilige Drei Koenige';
}
if (in_array($state, self::STATES_WITH_WOMENS_DAY, true)) {
$holidays[$this->dateKey($year, 3, 8, $timezone)] = 'Internationaler Frauentag';
}
if (in_array($state, self::STATES_WITH_CORPUS_CHRISTI, true)) {
$holidays[$easter->add(new DateInterval('P60D'))->format('Y-m-d')] = 'Fronleichnam';
}
if (in_array($state, self::STATES_WITH_ASSUMPTION, true)) {
$holidays[$this->dateKey($year, 8, 15, $timezone)] = 'Mariae Himmelfahrt';
}
if (in_array($state, self::STATES_WITH_REFORMATION, true)) {
$holidays[$this->dateKey($year, 10, 31, $timezone)] = 'Reformationstag';
}
if (in_array($state, self::STATES_WITH_ALL_SAINTS, true)) {
$holidays[$this->dateKey($year, 11, 1, $timezone)] = 'Allerheiligen';
}
if (in_array($state, self::STATES_WITH_REPENTANCE, true)) {
$holidays[$this->repentanceDay($year, $timezone)->format('Y-m-d')] = 'Buss- und Bettag';
}
return $holidays;
}
private function dateKey(int $year, int $month, int $day, DateTimeZone $timezone): string
{
return (new DateTimeImmutable(sprintf('%04d-%02d-%02d', $year, $month, $day), $timezone))->format('Y-m-d');
}
private function repentanceDay(int $year, DateTimeZone $timezone): DateTimeImmutable
{
$day = new DateTimeImmutable(sprintf('%04d-11-23', $year), $timezone);
while ((int) $day->format('N') !== 3) {
$day = $day->sub(new DateInterval('P1D'));
}
return $day;
}
}