# holidays: a Ruby gem for statutory holidays, observed days and regional calendars

> The holidays gem is a collection of Ruby methods for dealing with statutory and other holidays, extending Date and Time, with a separate definitions repository holding the calendars themselves. The interesting parts are the flags, since informal and observed holidays are both off by default, and the wildcard region syntax that pulls in a country and all of its sub-regions at once.

**holidays/holidays** — A collection of Ruby methods to deal with statutory and other holidays.  You deserve a holiday!

- Repository: https://github.com/holidays/holidays
- Stars: 879 · Forks: 290
- Language: Ruby
- License: NOASSERTION
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/holidays-holidays

## A gem and a separate definitions repository

The holidays gem is a collection of Ruby methods to deal with statutory and other holidays, and it extends Ruby's built-in Date and Time classes and supports custom holiday definition lists. The important architectural point is that the calendar data is not in the gem. All holiday definitions are maintained in a separate holidays/definitions repository, and the gem pulls it in as a git submodule, which the Makefile shows with a definitions target that adds the submodule pointing at the master branch of that repository. That split is what lets a calendar change be a change to the definitions rather than a new gem release, and it is why the Makefile has targets for pointing the submodule at a branch, resetting it to master and removing it. The gem itself installs the usual way, with the install command being:

```
gem install holidays
``` The gem itself is a normal Ruby gem with a gemspec, a lib directory, a definitions submodule, tests and a Rakefile, and the licence field on the repository is a custom one GitHub cannot classify, with the terms in the LICENSE file.

## The flags are off by default, and that matters

Two options control what you get back, and both default to off, which is the single most likely source of a bug when you start using this gem. The first is informal, for culturally recognised but non-statutory holidays such as Valentine's Day. By default the gem returns only statutory holidays, formally government-defined ones. The second is observed, for holidays that are observed on a different day than they actually occur, and by default no observed logic is applied. The consequence is that a query for a specific date can return an empty array and look like a bug when it is actually the default behaviour. For Canada Day, which fell on a Sunday, the observed query for Monday July 2 2007 in British Columbia returns Canada Day, while the same query without the flag returns nothing, and the query for July 1 returns it. The definitions syntax guide linked from the readme explains what formal and informal mean and how observed is defined, and it is the document to read before you draw conclusions from a query that returned nothing.

## Wildcard regions, and the sharp edge in them

The region syntax has a feature that is worth understanding before you rely on it. A region written with a trailing _ marker, such as:au_ or:ca_, is a wildcard, and it matches the parent country region and all of its sub-regions in a single call. A query for the 13th of March 2017 in:au_ returns Eight Hours Day in Tasmania, Labour Day in Victoria, March Public Holiday in South Australia and Canberra Day in the Australian Capital Territory, all of which are regional rather than national. The same date with the plain:au region returns an empty array, because none of those holidays are observed nation-wide. The sharp edge is stated explicitly: a wildcard always collapses to the top-level country region, the portion between the country prefix and the trailing _ marker is ignored, so:au_vic_ behaves identically to:au_ and loads every Australian sub-region rather than only Victoria's. There is currently no way to wildcard-match only the children of a sub-region, so if you need one state, you have to name it explicitly.

## The four query shapes cover most uses

The API is four methods and they compose. Holidays.on takes a single date and returns the holidays on it, and you can pass several regions in one call, so asking for the United States and France together on the first of January returns both New Year's Day and Jour de l'an, each tagged with the regions it applies to. You can also leave off regions entirely to get holidays for any region in the definitions, which is how you get a date that is a holiday somewhere without caring where. Holidays.between takes a from and a to date and returns everything in the range, which is the one to use for a month of calendar output. Holidays.next_holidays takes a count, a list of regions and a start date and looks forward, so asking for three from February 23 2016 in the US returns St. Patrick's Day, Good Friday and Easter Sunday. And Holidays.any_holidays_during_work_week? answers the scheduling question directly, where the work week is defined as Monday through Friday of the week the given date falls in, and it accepts the same informal and observed flags, so a business holiday on a Friday is caught even when the date you pass is the Monday before.

## Semantic versioning, with a caveat about definition changes

The gem follows semantic versioning, and the guarantee is scoped rather than blanket. It specifically covers methods in the top-most Holidays namespace, such as Holidays.on, and the core extensions to Ruby's Date and Time classes. What is not covered is everything else, and the note about definition changes is the part to read carefully. The maintainers consider definition changes to be minor bumps, meaning they are backwards compatible with your code but might give different holiday results. That is a deliberate and reasonable position, since a corrected holiday date is a data fix rather than an API change, and it means your code keeps working while the data shifts under it. If you have a test that asserts a specific holiday on a specific date, that test is testing the definitions repository as much as the gem, and it is the test most likely to break on a minor version bump. The tested Ruby versions are 3.3, 3.4, 4.0, and JRuby 10.0.5.0 and 10.1.0.0.

## Time zones are ignored, and the Makefile shows the working setup

There is one behavioural simplification that is worth knowing about before you build on this. Time zones are ignored, and the library assumes that all dates are within the same time zone. That is a reasonable scope for a calendar of dates, since most holiday questions are about a local date, but it means the gem will not tell you that a holiday in one zone falls on a different date in another. The Makefile is where the development workflow is described, and it is a good indicator of how the project is tested. There is a setup target that updates the definitions and runs bundle install, a generate target, and then a spread of test targets: a plain test, a smoke test, a contract test, an integration test, an end to end test, and a region specific target that takes a REGION argument. There is also a console target for poking at the library interactively, a build and push pair for the gem itself, and the clean and clean-defs targets that remove the built gem, the reports and the coverage output, and detach the definitions submodule. The presence of a contract test and an end to end test is a good sign for a library whose output is data.

## Conclusion

holidays suits a Ruby application that needs to know about public holidays in several jurisdictions, particularly one that has to handle the difference between a holiday's actual date and the day it is observed, since that is a common source of scheduling bugs. It does not suit an application that needs holiday data outside the definitions repository, and the wildcard region syntax has a sharp edge, since a wildcard always collapses to the top level country. Before you depend on it, read the definitions syntax guide to see how formal and informal are classified, and pin the gem version, because a definition change is treated as a minor bump and can change a holiday result without breaking your code.

## FAQ

### Why does Holidays.on return an empty array for a date I know is a holiday?

Two defaults are the usual cause. Informal holidays such as Valentine's Day are not returned unless you pass the :informal option, and holidays that are observed on a different day from the one they occur are not returned unless you pass the :observed option. The definitions syntax guide explains how formal and informal holidays are classified.

### What does a region written with a trailing _ marker do in the holidays gem?

A region written as :au_ is a wildcard that matches the parent country region and all of its sub-regions in one call. It always collapses to the top-level country, so :au_vic_ behaves identically to :au_, and there is currently no way to wildcard-match only the children of a sub-region.

### How do I check whether a holiday falls in a working week with the holidays gem?

Call Holidays.any_holidays_during_work_week? with a date, where the work week is Monday to Friday of the week that date falls in. It accepts the same :informal and :observed flags, so a holiday that is only observed on the Monday can be detected by passing the Monday and the :observed option.

### Where does the holidays gem get its holiday data?

All holiday definitions are maintained in the separate holidays/definitions repository and pulled into the gem as a git submodule, which the Makefile manages with targets to add it from a branch, reset it to master and remove it. A definition change counts as a minor version bump, since it is backwards compatible with your code but can give different holiday results.

## Sources

- [holidays/holidays on GitHub](https://github.com/holidays/holidays)
- [Issues](https://github.com/holidays/holidays/issues)
- [README](https://github.com/holidays/holidays/blob/master/README.md)
- [Releases](https://github.com/holidays/holidays/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/holidays-holidays
