diff --git a/UPGRADING.md b/UPGRADING.md index 0baf3eb9..7feb762e 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -88,3 +88,25 @@ Countries with region support now implement the `HasRegions` interface, which pr All regional countries now validate region codes in the constructor and throw `InvalidRegion` for unknown codes. If you were passing invalid region codes that were silently ignored in v1, they will now throw an exception. The Netherlands no longer accepts a `$region` constructor parameter (it was never used). + +## `Observable` trait methods no longer accept strings or `$year` + +In v1, `weekendToNextMonday()` and `sundayToNextMonday()` accepted a string date and a `$year` parameter: + +```php +// v1 +$this->weekendToNextMonday('01-01', $year); +$this->sundayToNextMonday('12-25', $year); +``` + +In v2, these methods only accept a `CarbonInterface` instance and the `$year` parameter has been removed: + +```php +// v2 +$this->weekendToNextMonday(CarbonImmutable::createFromDate($year, 1, 1)); +$this->sundayToNextMonday(CarbonImmutable::createFromDate($year, 12, 25)); +``` + +## Calendar lookup constants are now `protected` + +The calendar date lookup arrays on `Albania`, `Turkey`, and `India` (e.g. `eidAlFitr`, `eidAlAdha`, `holiHolidays`, etc.) have been changed from `public const` to `protected const`. If you were referencing these constants externally, use the country's public holiday API instead. diff --git a/src/Calendars/ChineseCalendar.php b/src/Calendars/ChineseCalendar.php index 63e1b928..59324c04 100644 --- a/src/Calendars/ChineseCalendar.php +++ b/src/Calendars/ChineseCalendar.php @@ -5,7 +5,9 @@ use Carbon\CarbonImmutable; use DateTimeZone; use IntlDateFormatter; +use Spatie\Holidays\Countries\Country; +/** @mixin Country */ trait ChineseCalendar { protected string $chineseCalendarTimezone = 'Asia/Shanghai'; diff --git a/src/Calendars/IndianCalendar.php b/src/Calendars/IndianCalendar.php index 829227d3..7501306d 100644 --- a/src/Calendars/IndianCalendar.php +++ b/src/Calendars/IndianCalendar.php @@ -2,15 +2,14 @@ namespace Spatie\Holidays\Calendars; -use Carbon\CarbonImmutable; use Carbon\CarbonPeriod; -use Carbon\Exceptions\InvalidFormatException; use Spatie\Holidays\Countries\Country; -use Spatie\Holidays\Exceptions\InvalidYear; /** @mixin Country */ trait IndianCalendar { + use ResolvesCalendarDates; + /** @return array */ protected function ashura(int $year, int $totalDays = 1): array { @@ -34,91 +33,4 @@ protected function ramzanIdHolidays(int $year, int $totalDays = 1): array { return $this->getMultiDayHoliday(self::ramzanIdHolidays, $year, $totalDays); } - - /** @param array $collection */ - protected function getSingleDayHoliday(array $collection, int $year): CarbonImmutable - { - $date = $collection[$year] ?? null; - - if ($date === null) { - throw InvalidYear::range($this->countryCode(), 1970, 2037); - } - - $date = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay(); - - if ($date === null) { - throw new InvalidFormatException('Invalid date for holiday'); - } - - return $date; - } - - /** - * @param array> $collection - * @return array - */ - protected function getMultiDayHoliday(array $collection, int $year, int $totalDays): array - { - $date = $collection[$year] ?? null; - - if ($date === null) { - throw InvalidYear::range($this->countryCode(), 1970, 2037); - } - - $overlap = $this->getOverlapping($collection, $year, $totalDays); - - if ($overlap) { - $period = $this->createPeriod($overlap, $year - 1, $totalDays); - - $date = [$period, $date]; - } - - if (! is_array($date)) { - return [$this->createPeriod($date, $year, $totalDays)]; - } - - // Twice a year - $periods = []; - $dates = $date; - - /** @var CarbonPeriod|string $date */ - foreach ($dates as $date) { - if ($date instanceof CarbonPeriod) { - $periods[] = $date; - - continue; - } - - $periods[] = $this->createPeriod($date, $year, $totalDays); - } - - return $periods; - } - - protected function createPeriod(string $date, int $year, int $totalDays): CarbonPeriod - { - $start = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay(); - $end = $start->addDays($totalDays - 1)->startOfDay(); - - return CarbonPeriod::create($start, '1 day', $end); - } - - /** @param array> $collection */ - protected function getOverlapping(array $collection, int $year, int $totalDays): ?string - { - if ($year === 1970) { - return null; - } - - $date = $collection[$year - 1] ?? throw InvalidYear::range($this->countryCode(), 1970, 2037); - - if (is_array($date)) { - $date = end($date); - } - - $start = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay(); - $end = $start?->addDays($totalDays - 1)->startOfDay(); - - return ($end?->year !== $year) ? (string) $date : null; - } } diff --git a/src/Calendars/IslamicCalendar.php b/src/Calendars/IslamicCalendar.php index 77ea1e0f..b9f52449 100644 --- a/src/Calendars/IslamicCalendar.php +++ b/src/Calendars/IslamicCalendar.php @@ -4,7 +4,6 @@ use Carbon\CarbonImmutable; use Carbon\CarbonPeriod; -use Carbon\Exceptions\InvalidFormatException; use DateTime; use DateTimeZone; use IntlDateFormatter; @@ -14,6 +13,8 @@ /** @mixin Country */ trait IslamicCalendar { + use ResolvesCalendarDates; + protected string $islamicCalendarTimezone = 'UTC'; /** @return array */ @@ -49,93 +50,6 @@ protected function prophetMuhammadBirthday(int $year): CarbonImmutable return $this->getSingleDayHoliday(self::prophetMuhammadBirthday, $year); } - /** @param array $collection */ - protected function getSingleDayHoliday(array $collection, int $year): CarbonImmutable - { - $date = $collection[$year] ?? null; - - if ($date === null) { - throw InvalidYear::range($this->countryCode(), 1970, 2037); - } - - $date = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay(); - - if ($date === null) { - throw new InvalidFormatException('Invalid date for holiday'); - } - - return $date; - } - - /** - * @param array> $collection - * @return array - */ - protected function getMultiDayHoliday(array $collection, int $year, int $totalDays): array - { - $date = $collection[$year] ?? null; - - if ($date === null) { - throw InvalidYear::range($this->countryCode(), 1970, 2037); - } - - $overlap = $this->getOverlapping($collection, $year, $totalDays); - - if ($overlap) { - $period = $this->createPeriod($overlap, $year - 1, $totalDays); - - $date = [$period, $date]; - } - - if (! is_array($date)) { - return [$this->createPeriod($date, $year, $totalDays)]; - } - - // Twice a year - $periods = []; - $dates = $date; - - /** @var CarbonPeriod|string $date */ - foreach ($dates as $date) { - if ($date instanceof CarbonPeriod) { - $periods[] = $date; - - continue; - } - - $periods[] = $this->createPeriod($date, $year, $totalDays); - } - - return $periods; - } - - protected function createPeriod(string $date, int $year, int $totalDays): CarbonPeriod - { - $start = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay(); - $end = $start->addDays($totalDays - 1)->startOfDay(); - - return CarbonPeriod::create($start, '1 day', $end); - } - - /** @param array> $collection */ - protected function getOverlapping(array $collection, int $year, int $totalDays): ?string - { - if ($year === 1970) { - return null; - } - - $date = $collection[$year - 1] ?? throw InvalidYear::range($this->countryCode(), 1970, 2037); - - if (is_array($date)) { - $date = end($date); - } - - $start = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay(); - $end = $start?->addDays($totalDays - 1)->startOfDay(); - - return ($end?->year !== $year) ? (string) $date : null; - } - public function setIslamicCalendarTimezone(string $islamicCalendarTimezone): static { $this->islamicCalendarTimezone = $islamicCalendarTimezone; diff --git a/src/Calendars/NepaliCalendar.php b/src/Calendars/NepaliCalendar.php index 6e3996ac..301241f9 100644 --- a/src/Calendars/NepaliCalendar.php +++ b/src/Calendars/NepaliCalendar.php @@ -3,11 +3,14 @@ namespace Spatie\Holidays\Calendars; use Carbon\CarbonImmutable; +use Spatie\Holidays\Countries\Country; /** * Nepal follows Bikram Sambat calendar. Bikram Sambat is a solar calendar based on ancient Hindu tradition. https://en.wikipedia.org/wiki/Vikram_Samvat * * Holiday in Nepal is celebrated according to the Bikram Sambat calendar, lunar calendar, and Gregorian calendar. + * + * @mixin Country */ trait NepaliCalendar { diff --git a/src/Calendars/ResolvesCalendarDates.php b/src/Calendars/ResolvesCalendarDates.php new file mode 100644 index 00000000..5e2a8e47 --- /dev/null +++ b/src/Calendars/ResolvesCalendarDates.php @@ -0,0 +1,99 @@ + $collection */ + protected function getSingleDayHoliday(array $collection, int $year): CarbonImmutable + { + $date = $collection[$year] ?? null; + + if ($date === null) { + throw InvalidYear::range($this->countryCode(), 1970, 2037); + } + + $date = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay(); + + if ($date === null) { + throw new InvalidFormatException('Invalid date for holiday'); + } + + return $date; + } + + /** + * @param array> $collection + * @return array + */ + protected function getMultiDayHoliday(array $collection, int $year, int $totalDays): array + { + $date = $collection[$year] ?? null; + + if ($date === null) { + throw InvalidYear::range($this->countryCode(), 1970, 2037); + } + + $overlap = $this->getOverlapping($collection, $year, $totalDays); + + if ($overlap) { + $period = $this->createPeriod($overlap, $year - 1, $totalDays); + + $date = [$period, $date]; + } + + if (! is_array($date)) { + return [$this->createPeriod($date, $year, $totalDays)]; + } + + $periods = []; + $dates = $date; + + /** @var CarbonPeriod|string $date */ + foreach ($dates as $date) { + if ($date instanceof CarbonPeriod) { + $periods[] = $date; + + continue; + } + + $periods[] = $this->createPeriod($date, $year, $totalDays); + } + + return $periods; + } + + protected function createPeriod(string $date, int $year, int $totalDays): CarbonPeriod + { + $start = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay(); + $end = $start->addDays($totalDays - 1)->startOfDay(); + + return CarbonPeriod::create($start, '1 day', $end); + } + + /** @param array> $collection */ + protected function getOverlapping(array $collection, int $year, int $totalDays): ?string + { + if ($year === 1970) { + return null; + } + + $date = $collection[$year - 1] ?? throw InvalidYear::range($this->countryCode(), 1970, 2037); + + if (is_array($date)) { + $date = end($date); + } + + $start = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay(); + $end = $start?->addDays($totalDays - 1)->startOfDay(); + + return ($end?->year !== $year) ? (string) $date : null; + } +} diff --git a/src/Concerns/Observable.php b/src/Concerns/Observable.php index ed18c9c8..86d2d71d 100644 --- a/src/Concerns/Observable.php +++ b/src/Concerns/Observable.php @@ -7,12 +7,8 @@ trait Observable { - protected function weekendToNextMonday(string|CarbonInterface $date, int $year): ?CarbonInterface + protected function weekendToNextMonday(CarbonInterface $date): ?CarbonInterface { - if (is_string($date)) { - $date = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")->startOfDay(); - } - if ($date->isWeekend()) { return $date->next('monday'); } @@ -20,12 +16,8 @@ protected function weekendToNextMonday(string|CarbonInterface $date, int $year): return null; } - protected function sundayToNextMonday(string|CarbonInterface $date, int $year): ?CarbonInterface + protected function sundayToNextMonday(CarbonInterface $date): ?CarbonInterface { - if (is_string($date)) { - $date = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")->startOfDay(); - } - if ($date->isSunday()) { return $date->next('monday'); } diff --git a/src/Countries/Albania.php b/src/Countries/Albania.php index 853bc984..c21a2333 100644 --- a/src/Countries/Albania.php +++ b/src/Countries/Albania.php @@ -14,7 +14,7 @@ class Albania extends Country implements HasTranslations, Islamic use IslamicCalendar; use Translatable; - public const eidAlFitr = [ + protected const eidAlFitr = [ 2024 => '04-10', 2025 => '03-30', 2026 => '03-20', @@ -28,7 +28,7 @@ class Albania extends Country implements HasTranslations, Islamic 2034 => '12-12', ]; - public const eidAlAdha = [ + protected const eidAlAdha = [ 2024 => '06-17', 2025 => '06-07', 2026 => '05-27', diff --git a/src/Countries/Ecuador.php b/src/Countries/Ecuador.php index 7768018d..b9480a84 100644 --- a/src/Countries/Ecuador.php +++ b/src/Countries/Ecuador.php @@ -52,7 +52,7 @@ public function nearestDay(int $year, int $month, int $day): CarbonInterface public function getChristmasHoliday(int $year): CarbonInterface { if ($year === 2022) { - $observedChristmasDay = $this->sundayToNextMonday('12-25', $year); + $observedChristmasDay = $this->sundayToNextMonday(CarbonImmutable::createFromDate($year, 12, 25)); if ($observedChristmasDay !== null) { return $observedChristmasDay; diff --git a/src/Countries/India.php b/src/Countries/India.php index 63756c00..f2cffa3f 100644 --- a/src/Countries/India.php +++ b/src/Countries/India.php @@ -15,7 +15,7 @@ class India extends Country * on Google Images for each year. The accuracy of the information has been double-checked. * A converter algorithm that will cover all years does not seem possible. */ - public const holiHolidays = [ + protected const holiHolidays = [ 1970 => '03-23', 1971 => '03-12', 1972 => '02-29', @@ -86,7 +86,7 @@ class India extends Country 2037 => '03-02', ]; - public const goodFridayHolidays = [ + protected const goodFridayHolidays = [ 1970 => '03-27', 1971 => '04-09', 1972 => '03-31', @@ -157,7 +157,7 @@ class India extends Country 2037 => '04-03', ]; - public const ramzanIdHolidays = [ + protected const ramzanIdHolidays = [ 1970 => '11-30', 1971 => '11-20', 1972 => '11-08', @@ -237,7 +237,7 @@ class India extends Country 2037 => '11-09', ]; - public const ramanavamiHolidays = [ + protected const ramanavamiHolidays = [ 1970 => '04-15', 1971 => '04-03', 1972 => '03-23', @@ -308,7 +308,7 @@ class India extends Country 2037 => '03-25', ]; - public const mahavirJayantiHolidays = [ + protected const mahavirJayantiHolidays = [ 1970 => '04-19', 1971 => '04-08', 1972 => '03-27', @@ -379,7 +379,7 @@ class India extends Country 2037 => '03-29', ]; - public const buddhaPurnimaHolidays = [ + protected const buddhaPurnimaHolidays = [ 1970 => '05-21', 1971 => '05-10', 1972 => '05-28', @@ -450,7 +450,7 @@ class India extends Country 2037 => '04-29', ]; - public const bakridHolidays = [ + protected const bakridHolidays = [ 1970 => '02-17', 1971 => '02-06', 1972 => '01-27', @@ -524,7 +524,7 @@ class India extends Country 2037 => '01-27', ]; - public const ashura = [ + protected const ashura = [ 1970 => '03-18', 1971 => '03-08', 1972 => '02-25', @@ -601,7 +601,7 @@ class India extends Country 2037 => '02-26', ]; - public const rakshabandhanHolidays = [ + protected const rakshabandhanHolidays = [ 1970 => '08-17', 1971 => '08-06', 1972 => '08-24', @@ -672,7 +672,7 @@ class India extends Country 2037 => '08-25', ]; - public const janmashtamiHolidays = [ + protected const janmashtamiHolidays = [ 1970 => '08-24', 1971 => '08-13', 1972 => '09-01', @@ -743,7 +743,7 @@ class India extends Country 2037 => '09-03', ]; - public const miladHolidays = [ + protected const miladHolidays = [ 1970 => '05-19', 1971 => '05-09', 1972 => '04-27', @@ -817,7 +817,7 @@ class India extends Country 2037 => '04-29', ]; - public const dussehraHolidays = [ + protected const dussehraHolidays = [ 1970 => '10-10', 1971 => '09-30', 1972 => '10-17', @@ -888,7 +888,7 @@ class India extends Country 2037 => '10-18', ]; - public const diwaliHolidays = [ + protected const diwaliHolidays = [ 1970 => '10-29', 1971 => '10-18', 1972 => '11-05', @@ -959,7 +959,7 @@ class India extends Country 2037 => '11-07', ]; - public const bhaiDujHolidays = [ + protected const bhaiDujHolidays = [ 1970 => '10-31', 1971 => '10-21', 1972 => '11-07', @@ -1030,7 +1030,7 @@ class India extends Country 2037 => '11-08', ]; - public const guruNanakHolidays = [ + protected const guruNanakHolidays = [ 1970 => '11-13', 1971 => '11-02', 1972 => '11-20', diff --git a/src/Countries/Jamaica.php b/src/Countries/Jamaica.php index 96803abc..3d9f3e80 100644 --- a/src/Countries/Jamaica.php +++ b/src/Countries/Jamaica.php @@ -38,7 +38,7 @@ protected function fixedHolidays(int $year): array foreach ($holidays as $name => $date) { $observedDay = match ($name) { 'Labour Day', 'Boxing Day' => $this->observed($name, $date, $year), - default => $this->sundayToNextMonday($date, $year), + default => $this->sundayToNextMonday($date), }; if ($observedDay) { diff --git a/src/Countries/Latvia.php b/src/Countries/Latvia.php index 78deceaf..cb784747 100644 --- a/src/Countries/Latvia.php +++ b/src/Countries/Latvia.php @@ -54,7 +54,7 @@ protected function observedHolidays(int $year): array ]; foreach ($holidays as $name => $date) { - $observedDay = $this->weekendToNextMonday($date, $year); + $observedDay = $this->weekendToNextMonday($date); if ($observedDay) { if ($name === 'Latvijas Republikas Neatkarības deklarācijas pasludināšanas diena') { diff --git a/src/Countries/NewZealand.php b/src/Countries/NewZealand.php index b4b7b27e..f66d921f 100644 --- a/src/Countries/NewZealand.php +++ b/src/Countries/NewZealand.php @@ -42,7 +42,7 @@ protected function observedHolidays(int $year): array "Day after New Year's Day" => $this->secondOfJanuary($year), 'Christmas Day' => $this->observedChristmasDay($year), 'Boxing Day' => $this->observedBoxingDay($year), - default => $this->weekendToNextMonday($date, $year), + default => $this->weekendToNextMonday($date), }; if ($observedDay) { diff --git a/src/Countries/NorthernIreland.php b/src/Countries/NorthernIreland.php index 23092823..83cb23c1 100644 --- a/src/Countries/NorthernIreland.php +++ b/src/Countries/NorthernIreland.php @@ -40,7 +40,7 @@ protected function observedHolidays(int $year): array $observedDay = match ($name) { 'Christmas Day' => $this->observedChristmasDay($year), 'Boxing Day' => $this->observedBoxingDay($year), - default => $this->weekendToNextMonday($date, $year), + default => $this->weekendToNextMonday($date), }; if ($observedDay) { diff --git a/src/Countries/Scotland.php b/src/Countries/Scotland.php index 097797a0..82e94513 100644 --- a/src/Countries/Scotland.php +++ b/src/Countries/Scotland.php @@ -41,7 +41,7 @@ protected function observedHolidays(int $year): array '2nd January' => $this->secondOfJanuary($year), 'Christmas Day' => $this->observedChristmasDay($year), 'Boxing Day' => $this->observedBoxingDay($year), - default => $this->weekendToNextMonday($date, $year), + default => $this->weekendToNextMonday($date), }; if ($observedDay) { diff --git a/src/Countries/SouthAfrica.php b/src/Countries/SouthAfrica.php index 43baec2a..9b271ee9 100644 --- a/src/Countries/SouthAfrica.php +++ b/src/Countries/SouthAfrica.php @@ -32,7 +32,7 @@ protected function allHolidays(int $year): array ]; foreach ($holidays as $name => $date) { - $observedDay = $this->sundayToNextMonday($date, $year); + $observedDay = $this->sundayToNextMonday($date); if ($observedDay) { $holidays[$name.' Observed'] = $observedDay; diff --git a/src/Countries/Turkey.php b/src/Countries/Turkey.php index 4ae1bc3a..d0a79e2a 100644 --- a/src/Countries/Turkey.php +++ b/src/Countries/Turkey.php @@ -22,7 +22,7 @@ class Turkey extends Country implements HasTranslations, Islamic * Ramadan and Sacrifice holidays vary for Turkey and other countries. * A converter algorithm that will cover all years does not seem possible. */ - public const eidAlFitr = [ + protected const eidAlFitr = [ 1970 => '12-01', 1971 => '11-20', 1972 => '11-08', @@ -99,7 +99,7 @@ class Turkey extends Country implements HasTranslations, Islamic 2037 => '11-09', ]; - public const eidAlAdha = [ + protected const eidAlAdha = [ 1970 => '02-17', 1971 => '02-16', 1972 => '01-27', diff --git a/src/Countries/Wales.php b/src/Countries/Wales.php index 4f204c27..43731ea6 100644 --- a/src/Countries/Wales.php +++ b/src/Countries/Wales.php @@ -39,7 +39,7 @@ protected function observedHolidays(int $year): array $observedDay = match ($name) { 'Christmas Day' => $this->observedChristmasDay($year), 'Boxing Day' => $this->observedBoxingDay($year), - default => $this->weekendToNextMonday($date, $year), + default => $this->weekendToNextMonday($date), }; if ($observedDay) {