Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 2 additions & 0 deletions src/Calendars/ChineseCalendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
92 changes: 2 additions & 90 deletions src/Calendars/IndianCalendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<CarbonPeriod> */
protected function ashura(int $year, int $totalDays = 1): array
{
Expand All @@ -34,91 +33,4 @@ protected function ramzanIdHolidays(int $year, int $totalDays = 1): array
{
return $this->getMultiDayHoliday(self::ramzanIdHolidays, $year, $totalDays);
}

/** @param array<string> $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<string|array<string>> $collection
* @return array<CarbonPeriod>
*/
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<string|array<string>> $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;
}
}
90 changes: 2 additions & 88 deletions src/Calendars/IslamicCalendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Carbon\CarbonImmutable;
use Carbon\CarbonPeriod;
use Carbon\Exceptions\InvalidFormatException;
use DateTime;
use DateTimeZone;
use IntlDateFormatter;
Expand All @@ -14,6 +13,8 @@
/** @mixin Country */
trait IslamicCalendar
{
use ResolvesCalendarDates;

protected string $islamicCalendarTimezone = 'UTC';

/** @return array<CarbonPeriod> */
Expand Down Expand Up @@ -49,93 +50,6 @@ protected function prophetMuhammadBirthday(int $year): CarbonImmutable
return $this->getSingleDayHoliday(self::prophetMuhammadBirthday, $year);
}

/** @param array<string> $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<string|array<string>> $collection
* @return array<CarbonPeriod>
*/
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<string|array<string>> $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;
Expand Down
3 changes: 3 additions & 0 deletions src/Calendars/NepaliCalendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
99 changes: 99 additions & 0 deletions src/Calendars/ResolvesCalendarDates.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

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 ResolvesCalendarDates
{
/** @param array<string> $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<string|array<string>> $collection
* @return array<CarbonPeriod>
*/
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<string|array<string>> $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;
}
}
12 changes: 2 additions & 10 deletions src/Concerns/Observable.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,17 @@

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');
}

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');
}
Expand Down
Loading