Skip to content

Commit

Permalink
Add getInRange function (#150)
Browse files Browse the repository at this point in the history
* add getInRange function

* Update Holidays.php

* Update Holidays.php

---------

Co-authored-by: Petr Katerinak <[email protected]>
  • Loading branch information
inDeev and Petr Katerinak committed Jun 24, 2024
1 parent 94d6e6d commit 26644a6
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 1 deletion.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,19 @@ use Spatie\Holidays\Holidays;
$holidays = Holidays::for(country: 'be', year: 2024))->get();
```

### Getting holidays in a specific language
### 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');
```

### Getting holidays in a specific language

```php
$holidays = Holidays::for(country: 'be', locale: 'fr'))->get();
```

Expand Down
35 changes: 35 additions & 0 deletions src/Countries/Country.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,41 @@ public function get(int $year, ?string $locale = null): array
return $translatedHolidays;
}

/** @return array<string, string> 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());
Expand Down
39 changes: 39 additions & 0 deletions src/Holidays.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ protected function __construct(
protected Country $country,
protected int $year,
protected ?string $locale = null,
protected ?CarbonImmutable $from = null,
protected ?CarbonImmutable $to = null,
) {
}

Expand Down Expand Up @@ -45,6 +47,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<string, string> 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) {
Expand Down
17 changes: 17 additions & 0 deletions tests/HolidaysTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,23 @@
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'],
]);

it('can get the country is supported', function () {
$result = Holidays::has(country: 'be');
expect($result)->toBeTrue();
Expand Down

0 comments on commit 26644a6

Please sign in to comment.