spatie/holidays
Calculate public holidays for supported countries using ISO codes or country classes. Get an array of Holiday objects with name, CarbonImmutable date, and type (e.g., national). PHP 8.4+ package by Spatie, with extensible country definitions.
Installation:
composer require spatie/holidays
Requires PHP 8.4+.
First Use Case: Fetch holidays for a country (e.g., Belgium) in the current year:
use Spatie\Holidays\Holidays;
$holidays = Holidays::for('be')->get();
foreach ($holidays as $holiday) {
echo $holiday->name . ' (' . $holiday->date->format('Y-m-d') . ')';
}
Outputs all Belgian holidays with their names and dates.
Key Entry Points:
Holidays::for('country_code')->get(): Get all holidays for a country.Holidays::for('country_code')->isHoliday('2024-01-01'): Check if a specific date is a holiday.Holidays::for('country_code')->getUpcoming(3): Get the next 3 upcoming holidays.getInRange(), getLongWeekends(), and getName() methods for common workflows.Fetching Holidays for Business Logic:
// Check if a date is a holiday (e.g., for leave approval)
if (Holidays::for('us')->isHoliday($request->date)) {
return back()->withError('Holiday detected. Approval denied.');
}
Date Range Filtering:
// Get holidays for Q1 2024 (e.g., for scheduling)
$q1Holidays = Holidays::for('jp')->getInRange('2024-01-01', '2024-03-31');
Localization:
// Fetch holidays in French (e.g., for multilingual apps)
$frHolidays = Holidays::for('ca', locale: 'fr')->get();
Regional Holidays:
// Germany has state-specific holidays (e.g., for regional events)
$bavarianHolidays = Holidays::for('de', region: 'DE-BW')->get();
Long Weekends for Travel Apps:
// Identify long weekends (e.g., for travel promotions)
$longWeekends = Holidays::for('au')->getLongWeekends();
foreach ($longWeekends as $weekend) {
echo "Weekend: {$weekend->startDate} to {$weekend->endDate}";
}
Caching: Cache holiday results for performance (e.g., using Laravel's cache):
$holidays = Cache::remember("holidays_{$country}_{$year}", now()->addYear(), function () use ($country, $year) {
return Holidays::for($country, year: $year)->get();
});
API Responses: Serialize holidays for JSON APIs:
return response()->json(Holidays::for('in')->get());
Validation: Use holidays to validate date ranges (e.g., in forms):
$validator->rule(function ($attribute, $value, $fail) {
if (Holidays::for('gb')->isHoliday($value)) {
$fail('Holidays are not allowed.');
}
});
Testing: Mock holidays in tests:
$this->mock(Holidays::class, function ($mock) {
$mock->shouldReceive('for')->andReturnSelf();
$mock->shouldReceive('isHoliday')->andReturn(true);
});
Country Code Sensitivity:
'us' for USA, not 'usa').Holidays::has('country_code').Year Range Limits:
Regional Holiday Overrides:
DE-BW) override national holidays if they conflict. Always specify a region if needed.Date Formatting:
CarbonImmutable for dates. Ensure your code handles immutable dates (e.g., avoid modifying them directly).Locale Fallbacks:
Observed Holidays:
HasObservedHolidays trait handles this, but custom logic may be needed for edge cases.Empty Results:
Holidays::has('xx').Missing Regional Holidays:
'DE-BW' for Bavaria, not 'bw').Country::regions() to list valid regions for a country.Date Mismatches:
Holidays::for('country')->getName('2024-01-01') to debug holiday names/dates.Performance:
getInRange() instead of filtering after fetching all holidays.Custom Holiday Logic:
Country class to add support for unsupported countries:
class MyCountry extends Country {
public function countryCode(): string { return 'xx'; }
protected function allHolidays(int $year): array {
return [Holiday::national('Custom Holiday', "{$year}-12-25")];
}
}
CountryRegistry.php.Calendar Systems:
IslamicCalendar) and defining lookup tables.Holiday Types:
HolidayType enum or add custom types by modifying the Holiday class.Translations:
lang/{countryCode}/{locale}/holidays.json.Testing:
expect(formatDates($holidays))->toMatchSnapshot();
vendor/bin/pest --update-snapshots to update snapshots after changes.Combine with Carbon:
use Carbon\CarbonImmutable;
$holidayDate = CarbonImmutable::parse('2024-01-01');
if (Holidays::for('be')->isHoliday($holidayDate)) {
// Logic for holidays
}
Group Holidays by Type:
$national = array_filter($holidays, fn($h) => $h->type === HolidayType::National);
$regional = array_filter($holidays, fn($h) => $h->type === HolidayType::Regional);
Dynamic Year Handling:
$year = now()->year;
$holidays = Holidays::for('in', year: $year)->get();
Holiday-Free Date Ranges:
function getHolidayFreeDates(string $country, string $start, string $end): array {
$allDates = collect(range($start, $end));
$holidays = Holidays::for($country)->getInRange($start, $end);
return $allDates->reject(fn($date) => $holidays->contains(fn($h) => $h->date->
How can I help you explore Laravel packages today?