Initial commit
This commit is contained in:
117
api/includes/CzechHolidays.php
Normal file
117
api/includes/CzechHolidays.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Czech Holidays & Work Fund Calculator
|
||||
*
|
||||
* Provides Czech public holidays (including movable Easter dates)
|
||||
* and monthly work fund calculations.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
class CzechHolidays
|
||||
{
|
||||
/** @var array<int, list<string>> Static cache for holidays by year */
|
||||
private static array $holidayCache = [];
|
||||
|
||||
/**
|
||||
* Get all Czech public holidays for a given year.
|
||||
* Returns array of 'Y-m-d' strings (11 fixed + 2 Easter-based).
|
||||
* Results are cached per-request to avoid recalculation.
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
public static function getHolidays(int $year): array
|
||||
{
|
||||
if (isset(self::$holidayCache[$year])) {
|
||||
return self::$holidayCache[$year];
|
||||
}
|
||||
// Fixed holidays
|
||||
$holidays = [
|
||||
sprintf('%04d-01-01', $year), // Den obnovy samostatného českého státu
|
||||
sprintf('%04d-05-01', $year), // Svátek práce
|
||||
sprintf('%04d-05-08', $year), // Den vítězství
|
||||
sprintf('%04d-07-05', $year), // Den slovanských věrozvěstů Cyrila a Metoděje
|
||||
sprintf('%04d-07-06', $year), // Den upálení mistra Jana Husa
|
||||
sprintf('%04d-09-28', $year), // Den české státnosti
|
||||
sprintf('%04d-10-28', $year), // Den vzniku samostatného československého státu
|
||||
sprintf('%04d-11-17', $year), // Den boje za svobodu a demokracii
|
||||
sprintf('%04d-12-24', $year), // Štědrý den
|
||||
sprintf('%04d-12-25', $year), // 1. svátek vánoční
|
||||
sprintf('%04d-12-26', $year), // 2. svátek vánoční
|
||||
];
|
||||
|
||||
// Easter-based holidays (Anonymous Gregorian algorithm)
|
||||
$easterSunday = self::getEasterSunday($year);
|
||||
$goodFriday = date('Y-m-d', strtotime($easterSunday . ' -2 days'));
|
||||
$easterMonday = date('Y-m-d', strtotime($easterSunday . ' +1 day'));
|
||||
$holidays[] = $goodFriday; // Velký pátek
|
||||
$holidays[] = $easterMonday; // Velikonoční pondělí
|
||||
|
||||
sort($holidays);
|
||||
self::$holidayCache[$year] = $holidays;
|
||||
return $holidays;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a date is a Czech public holiday.
|
||||
*/
|
||||
public static function isHoliday(string $date): bool
|
||||
{
|
||||
$year = (int)date('Y', strtotime($date));
|
||||
$formatted = date('Y-m-d', strtotime($date));
|
||||
return in_array($formatted, self::getHolidays($year), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of business days (Mon-Fri, excluding holidays) in a month.
|
||||
*/
|
||||
public static function getBusinessDaysInMonth(int $year, int $month): int
|
||||
{
|
||||
$holidays = self::getHolidays($year);
|
||||
$daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year);
|
||||
$businessDays = 0;
|
||||
|
||||
for ($day = 1; $day <= $daysInMonth; $day++) {
|
||||
$date = sprintf('%04d-%02d-%02d', $year, $month, $day);
|
||||
$dayOfWeek = (int)date('N', strtotime($date)); // 1=Mon, 7=Sun
|
||||
if ($dayOfWeek <= 5 && !in_array($date, $holidays, true)) {
|
||||
$businessDays++;
|
||||
}
|
||||
}
|
||||
|
||||
return $businessDays;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get monthly work fund in hours (business days × 8).
|
||||
*/
|
||||
public static function getMonthlyWorkFund(int $year, int $month): float
|
||||
{
|
||||
return self::getBusinessDaysInMonth($year, $month) * 8.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate Easter Sunday date using the Anonymous Gregorian algorithm.
|
||||
* Returns 'Y-m-d' string.
|
||||
*/
|
||||
private static function getEasterSunday(int $year): string
|
||||
{
|
||||
$a = $year % 19;
|
||||
$b = intdiv($year, 100);
|
||||
$c = $year % 100;
|
||||
$d = intdiv($b, 4);
|
||||
$e = $b % 4;
|
||||
$f = intdiv($b + 8, 25);
|
||||
$g = intdiv($b - $f + 1, 3);
|
||||
$h = (19 * $a + $b - $d - $g + 15) % 30;
|
||||
$i = intdiv($c, 4);
|
||||
$k = $c % 4;
|
||||
$l = (32 + 2 * $e + 2 * $i - $h - $k) % 7;
|
||||
$m = intdiv($a + 11 * $h + 22 * $l, 451);
|
||||
$month = intdiv($h + $l - 7 * $m + 114, 31);
|
||||
$day = (($h + $l - 7 * $m + 114) % 31) + 1;
|
||||
|
||||
return sprintf('%04d-%02d-%02d', $year, $month, $day);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user