110 lines
4.5 KiB
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;
|
|
}
|
|
}
|