From 447203b07dacd4799a41db3da2f17bbea246a0d8 Mon Sep 17 00:00:00 2001 From: Petr Katerinak Date: Sat, 20 Jan 2024 18:53:47 +0100 Subject: [PATCH 1/3] add getInRange function --- README.md | 10 ++++++++++ src/Countries/Country.php | 35 +++++++++++++++++++++++++++++++++++ src/Holidays.php | 39 +++++++++++++++++++++++++++++++++++++++ tests/HolidaysTest.php | 16 ++++++++++++++++ 4 files changed, 100 insertions(+) diff --git a/README.md b/README.md index 8bc3564e3..bc1182eb5 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,16 @@ use Spatie\Holidays\Holidays; $holidays = Holidays::for(country: 'be', year: 2024))->get(); ``` +### Getting holidays between two dates + +You can also get all holidays between two dates (inclusive). + +```php +use Spatie\Holidays\Holidays; + +$holidays = Holidays::for('be')->getInRange('2023-06-01', '2024-05-31'); +``` + ### Determining if a date is a holiday If you need to see if a date is a holiday, you can use the `isHoliday` method. diff --git a/src/Countries/Country.php b/src/Countries/Country.php index 3a09768db..2cf7dc804 100644 --- a/src/Countries/Country.php +++ b/src/Countries/Country.php @@ -35,6 +35,41 @@ public function get(int $year): array return $allHolidays; } + /** @return array date => name */ + public function getInRange(?CarbonImmutable $from, ?CarbonImmutable $to): array + { + $from ??= CarbonImmutable::now()->startOfYear(); + $to ??= CarbonImmutable::now()->endOfYear(); + + $this->ensureYearCanBeCalculated($from->year); + $this->ensureYearCanBeCalculated($to->year); + + $allHolidays = []; + + for ($year = $from->year; $year <= $to->year; $year++) { + $yearHolidays = $this->get($year); + /** + * @var string $name + * @var CarbonImmutable $date + */ + foreach ($yearHolidays as $name => $date) { + if ($date->between($from, $to)) { + $allHolidays[] = ['date' => $date, 'name' => $name]; + } + } + } + + usort($allHolidays, static fn (array $a, array $b) => $a['date'] <=> $b['date']); + + $mappedHolidays = []; + /** @var array{date: CarbonImmutable, name: string} $holiday */ + foreach ($allHolidays as $holiday) { + $mappedHolidays[$holiday['date']->toDateString()] = $holiday['name']; + } + + return $mappedHolidays; + } + public static function make(): static { return new static(...func_get_args()); diff --git a/src/Holidays.php b/src/Holidays.php index 775592df5..b7ede1c7a 100755 --- a/src/Holidays.php +++ b/src/Holidays.php @@ -14,6 +14,8 @@ class Holidays protected function __construct( protected Country $country, protected int $year, + protected ?CarbonImmutable $from = null, + protected ?CarbonImmutable $to = null ) { } @@ -39,6 +41,43 @@ public function get(Country|string|null $country = null, ?int $year = null): arr ->toArray(); } + /** + * getInRange method allows you to pick holidays in a range of dates, + * - dates are inclusive. + * - dates are swappable, lower date could be passed as second argument. + * - dates could be a CarbonInterface or a string. + * - acceptable strings formats are 'Y-m-d' or 'Y-m' or 'Y' + * - if passed string is 'Y-m' or 'Y' it will be converted to first(from) / last{to} day of the month(from) / year(to) + * E.g. to retrieve all holidays in between + * - 2020-01-01 and 2024-12-31, you could use: getInRange('2020-01-01', '2024-12-31'), getInRange('2020-01', '2024-12') or getInRange('2020', '2024') + * - 2024-06-01 and 2025-05-30, you could use: getInRange('2024-06-01', '2025-05-30'), getInRange('2024-06', '2025-05') + * @return array date => name + */ + public function getInRange(CarbonInterface|string $from, CarbonInterface|string $to): array + { + if (! $from instanceof CarbonImmutable) { + $from = match (strlen($from)) { + 4 => CarbonImmutable::parse($from . '-01-01'), + 7 => CarbonImmutable::parse($from . '-01'), + default => CarbonImmutable::parse($from), + }; + } + + if (! $to instanceof CarbonImmutable) { + $to = match (strlen($to)) { + 4 => CarbonImmutable::parse($to . '-12-31'), + 7 => CarbonImmutable::parse($to)->endOfMonth(), + default => CarbonImmutable::parse($to), + }; + } + + if ($from->gt($to)) { + [$from, $to] = [$to, $from]; + } + + return $this->country->getInRange($from, $to); + } + public function isHoliday(CarbonInterface|string $date, Country|string|null $country = null): bool { if (! $date instanceof CarbonImmutable) { diff --git a/tests/HolidaysTest.php b/tests/HolidaysTest.php index 2477e6053..94e8a3c2c 100644 --- a/tests/HolidaysTest.php +++ b/tests/HolidaysTest.php @@ -83,3 +83,19 @@ $result = Holidays::for('be')->getName(CarbonImmutable::parse('2024-01-02')); expect($result)->toBeNull(); }); + +it('can get all holidays between two dates', function (string|CarbonImmutable $from, string|CarbonImmutable $to, int $expectedCount, string $firstName, string $lastName) { + $holidays = Holidays::for('be')->getInRange($from, $to); + + expect($holidays)->toBeArray(); + expect($holidays)->toHaveCount($expectedCount); + expect(reset($holidays))->toBe($firstName); + expect(end($holidays))->toBe($lastName); +})->with([ + ['2020', '2024', 50, 'Nieuwjaar', 'Kerstmis'], + ['2024-06', '2025-05', 9, 'Nationale Feestdag', 'OLH Hemelvaart'], + ['2023-06-01', '2024-05-30', 10, 'Nationale Feestdag', 'Pinkstermaandag'], + ['2024-05-30', '2023-06-01', 10, 'Nationale Feestdag', 'Pinkstermaandag'], + [CarbonImmutable::parse('2023-06-01'), CarbonImmutable::parse('2024-05-30'), 10, 'Nationale Feestdag', 'Pinkstermaandag'], + [CarbonImmutable::parse('2023-06-01'), '2024-05', 10, 'Nationale Feestdag', 'Pinkstermaandag'], +]); From 7c5aea899bb4cac48075cbc2644472cac0ee4b47 Mon Sep 17 00:00:00 2001 From: Petr Katerinak <33215381+inDeev@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:05:52 +0100 Subject: [PATCH 2/3] Update Holidays.php --- src/Holidays.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Holidays.php b/src/Holidays.php index 663fc9e7b..aee101ccf 100755 --- a/src/Holidays.php +++ b/src/Holidays.php @@ -15,8 +15,8 @@ protected function __construct( protected Country $country, protected int $year, protected ?CarbonImmutable $from = null, - protected ?CarbonImmutable $to = null - protected ?string $locale = null, + protected ?CarbonImmutable $to = null, + protected ?string $locale = null ) { } From 621e1919b8566db41be556c5088a6b5fdad6b6ba Mon Sep 17 00:00:00 2001 From: Petr Katerinak <33215381+inDeev@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:09:14 +0100 Subject: [PATCH 3/3] Update Holidays.php --- src/Holidays.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Holidays.php b/src/Holidays.php index aee101ccf..50a11ab6f 100755 --- a/src/Holidays.php +++ b/src/Holidays.php @@ -14,9 +14,9 @@ class Holidays protected function __construct( protected Country $country, protected int $year, + protected ?string $locale = null, protected ?CarbonImmutable $from = null, protected ?CarbonImmutable $to = null, - protected ?string $locale = null ) { }