This package can calculate public holidays for a country.
use Spatie\Holidays\Holidays;
$holidays = Holidays::for('be')->get();
$holidays[0]->name; // 'Nieuwjaar'
$holidays[0]->date; // CarbonImmutable('2024-01-01')
$holidays[0]->type; // HolidayType::NationalWe invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.
We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.
You can install the package via composer:
composer require spatie/holidaysThis package requires PHP 8.4+.
We support the countries listed in this directory. If you want to add a country, please create a pull request. See Adding a new country for a guide.
You can get all holidays for a country by using the get method. It returns an array of Holiday objects.
use Spatie\Holidays\Holidays;
$holidays = Holidays::for('be')->get();
foreach ($holidays as $holiday) {
$holiday->name; // 'Nieuwjaar'
$holiday->date; // CarbonImmutable instance
$holiday->type; // HolidayType::National
}You can pass a country instance or an ISO 3166-1 alpha-2 code:
use Spatie\Holidays\Countries\Belgium;
$holidays = Holidays::for(Belgium::make())->get();
$holidays = Holidays::for('be')->get();The Holiday object implements JsonSerializable:
json_encode($holidays[0]);
// {"name":"Nieuwjaar","date":"2024-01-01","type":"national","region":null}$holidays = Holidays::for(country: 'be', year: 2024)->get();The getInRange method returns all holidays between two dates (inclusive). Dates are swappable — the lower date is always used as the start.
$holidays = Holidays::for('be')->getInRange('2024-01-01', '2024-12-31');You can also use shorthand formats:
$holidays = Holidays::for('be')->getInRange('2024', '2025'); // full years
$holidays = Holidays::for('be')->getInRange('2024-06', '2025-05'); // year-month$holidays = Holidays::for(country: 'be', locale: 'fr')->get();If no translation file exists for the given locale, the original holiday names are returned.
Some countries have region-specific holidays. You can pass a region code to the for method:
$holidays = Holidays::for('de', year: 2024, region: 'DE-BW')->get();Or use the country class directly:
use Spatie\Holidays\Countries\Germany;
$holidays = Holidays::for(Germany::make('DE-BW'), year: 2024)->get();To discover which regions a country supports:
use Spatie\Holidays\Countries\Germany;
Germany::regions(); // ['DE-BW', 'DE-BY', 'DE-BE', ...]Countries that support regions: Australia, Bosnia and Herzegovina, France, Germany, Malaysia, Spain, Switzerland.
Holidays::for('be')->isHoliday('2024-01-01'); // trueHolidays::for('be')->isTodayHoliday(); // true or false$holidays = Holidays::for('be')->getUpcoming(3);
// Returns the next 3 upcoming holidays
foreach ($holidays as $holiday) {
echo $holiday->date; // CarbonImmutable
echo $holiday->name;
}$longWeekends = Holidays::for('de', 2024)->getLongWeekends();
// With custom minimum days (default: 4)
$longWeekends = Holidays::for('de', 2024)->getLongWeekends(3);
foreach ($longWeekends as $weekend) {
echo $weekend->startDate; // First day of the long weekend
echo $weekend->endDate; // Last day of the long weekend
echo $weekend->dayCount; // Number of days
echo $weekend->holidays; // Array of Holiday objects
}Holidays::for('be')->getName('2024-01-01'); // 'Nieuwjaar'Holidays::has('be'); // true
Holidays::has('unknown'); // falseThis is a community driven package. If you find any errors, please create a pull request with the fix, or at least open an issue.
Create a new class in src/Countries that extends Country. At minimum, you need to implement countryCode() and allHolidays():
use Spatie\Holidays\Countries\Country;
use Spatie\Holidays\Holiday;
use Spatie\Holidays\HolidayType;
class MyCountry extends Country
{
public function countryCode(): string
{
return 'xx'; // ISO 3166-1 alpha-2 code
}
protected function allHolidays(int $year): array
{
return [
Holiday::national("New Year's Day", "{$year}-01-01"),
Holiday::national('Christmas', "{$year}-12-25"),
];
}
}The Holiday::national() helper accepts both strings and CarbonImmutable instances. For Easter-based holidays, use the easter() or orthodoxEaster() helpers:
protected function allHolidays(int $year): array
{
$easter = $this->easter($year);
return [
Holiday::national('Good Friday', $easter->subDays(2)),
Holiday::national('Easter Monday', $easter->addDay()),
];
}For relative dates, use CarbonImmutable::parse():
Holiday::national('Labor Day', CarbonImmutable::parse("first monday of September {$year}"));If your country defines holidays in a non-English language, override defaultLocale():
protected function defaultLocale(): string
{
return 'de';
}In src/CountryRegistry.php, add your ISO country code and country class to the MAP constant.
If your country has region-specific holidays, implement the HasRegions interface:
use Spatie\Holidays\Contracts\HasRegions;
use Spatie\Holidays\Exceptions\InvalidRegion;
class MyCountry extends Country implements HasRegions
{
protected function __construct(protected ?string $region = null)
{
if ($region !== null && ! in_array($region, static::regions())) {
throw InvalidRegion::notFound($region);
}
}
public static function regions(): array
{
return ['XX-A', 'XX-B', 'XX-C'];
}
public function region(): ?string
{
return $this->region;
}
protected function allHolidays(int $year): array
{
return array_merge(
$this->nationalHolidays($year),
$this->regionHolidays($year),
);
}
protected function regionHolidays(int $year): array
{
return match ($this->region) {
'XX-A' => ['Regional Day' => CarbonImmutable::createFromDate($year, 6, 1)],
default => [],
};
}
}If your country moves holidays that fall on a weekend to the next weekday, use the HasObservedHolidays trait:
use Spatie\Holidays\Concerns\HasObservedHolidays;
use Spatie\Holidays\Holiday;
class MyCountry extends Country
{
use HasObservedHolidays;
protected function allHolidays(int $year): array
{
$holidays = [
Holiday::national("New Year's Day", "{$year}-01-01"),
];
// Example: if New Year's Day falls on a weekend, add an observed day
$newYear = $this->sundayToNextMonday($holidays[0]->date);
if ($newYear !== null) {
$holidays[] = Holiday::observed("New Year's Day (Observed)", $newYear);
}
return $holidays;
}
}The trait provides these methods (each returns null if no shift applies):
weekendToNextMonday(CarbonInterface $date)— shifts Saturday/Sunday to MondaysundayToNextMonday(CarbonInterface $date)— shifts Sunday to MondayobservedChristmasDay(CarbonInterface $date)— Saturday to Monday, Sunday to TuesdayobservedBoxingDay(CarbonInterface $date)— Saturday to Monday, Sunday to Tuesday
The Holiday class supports different holiday types:
use Spatie\Holidays\Holiday;
use Spatie\Holidays\HolidayType;
Holiday::national('New Year', "{$year}-01-01"); // Default type
Holiday::regional('Regional Day', "{$year}-06-01", 'XX-RE'); // With region
Holiday::religious('Easter', $easterDate); // Religious holidays
Holiday::observed('Observed Day', $observedDate); // Observed holidays
Holiday::banked('Bank Holiday', "{$year}-12-25"); // Bank holidaysAvailable types in HolidayType enum: National, Regional, Religious, Observed, Banked.
For countries that use Islamic, Chinese, Indian, or Nepali calendar dates, use the corresponding calendar trait. These traits rely on precomputed lookup tables defined as protected const arrays on your country class:
use Spatie\Holidays\Calendars\IslamicCalendar;
use Spatie\Holidays\Contracts\Islamic;
class MyCountry extends Country implements Islamic
{
use IslamicCalendar;
protected const eidAlFitr = [
2024 => '04-10',
2025 => '03-30',
// ...
];
protected const eidAlAdha = [
2024 => '06-16',
2025 => '06-06',
// ...
];
}Countries with lookup tables must declare their supported year range:
protected function supportedYearRange(): array
{
return [2024, 2037]; // [min, max] based on your lookup data
}For multi-day holidays (like Eid), use convertPeriods() to expand a CarbonPeriod into individual named days:
$this->convertPeriods('Eid al-Fitr', $year, $this->eidAlFitr($year)[0], includeEve: true);Available calendar traits: IslamicCalendar, ChineseCalendar, IndianCalendar, NepaliCalendar.
To add translations for a country, create a JSON file at lang/{countryCode}/{locale}/holidays.json:
{
"New Year's Day": "Jour de l'An",
"Christmas": "Noël"
}The keys must match the holiday names returned by allHolidays().
- Create a test file in
tests/Countries/:
use Carbon\CarbonImmutable;
use Spatie\Holidays\Holidays;
it('can calculate my country holidays', function () {
CarbonImmutable::setTestNow('2024-01-01');
$holidays = Holidays::for(country: 'xx')->get();
expect($holidays)
->toBeArray()
->not()->toBeEmpty();
expect(formatDates($holidays))->toMatchSnapshot();
});- Run
vendor/bin/pest --update-snapshotsto generate the snapshot. - Verify the generated snapshot in
tests/.pest/snapshots/is correct.
composer testPlease see CHANGELOG for more information on what has changed recently.
Please see UPGRADING for how to upgrade to a new major version.
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.
