Procedurally calculated holiday dates in JS
Cover photo by Towfiqu barbhuiya on Unsplash
Have you worked on a project that required a periodically updated list of holidays? How did you find those dates?
I’m seeing a pattern
I’ve seen a lot of databases and one table that consistently pops up in corporate databases is the “holiday” table. HR will store paid company holidays in it, or marketing will use it to schedule email blasts, or it might be used to automatically populate the calendar on the company’s public website.
What is interesting about this database table is that it is usually manually populated periodically…usually when something breaks and IT realizes it’s time to update the holiday list again. And that may be totally find for your project.
The plot thickens
A few years ago I was working on a project that was using one such holiday table for marketing purposes. I decided to see what other solutions were out there. Googling the matter, I came across several PAID services offering a holiday API. You paid to access an api that would return dates of holidays. It seemed that even companies focused on solving this problem were just using their own manually updated holiday list and charging you to access it with the promise of keeping it up to date.
Is there a better way?
Do you really need an API to provide easily consumable holiday dates? As it turns out you can procedurally determine the date of any holiday. While some holidays always fall on the same date, most holidays are determined by some algorithm.
Federal Holidays
Federal holidays in the United States are created by law, meaning there are defined procedures to determine the date of a given holiday. What’s more, there are procedures defined to determine what day a holiday should be observed should the holiday fall on a weekend (so employees can still enjoy a day off).
For example:
- Memorial Day is the last Monday of May
- Thanksgiving Day is the last Thursday of November
- Christmas Day is always the 25th of December but the federally observed day is the nearest weekday
Religious Holidays
Similar to federal holidays, there are rules defined by religions for when each religious holiday should be observed. Some branches of a religion might celebrate the same holiday on a different date governed by a different procedure.
Other Holidays
Some observed holidays are not defined by the government or religions but there at least exists some rule so everyone knows when to observe it.
Easter
Most holidays are easy enough to calculate. This one, though, might be the cause of so many just giving up and manually punching in the date for holidays each year. The good news, is we only have to write the logic to determine it once.
Easter has several methods of calculation depending on where you are in the world. I’ll describe the calculation used in the United States. It’s calculated using the “Metonic Cycle” with logic determined by the Easter computus.
The gist is this. There is an association between a “Golden number” and a “Paschal full moon date”. (Technically the golden number is associated with a number called Epact which determines the full moon date, but all these numbers have a 1 to 1 association so we can just jump from golden number to the full moon date.)
The association is as follows:
Golden Number Paschal Full Moon Date
1..............14 April
2...............3 April
3..............23 March
4..............11 April
5..............31 March
6..............18 April
7...............8 April
8..............28 March
9..............16 April
10..............5 April
11.............25 March
12.............13 April
13..............2 April
14.............22 March
15.............10 April
16.............30 March
17.............17 April
18..............7 April
19.............27 March
First you need to determine the Golden number. This is done by taking the modulus of the year divided by 19, then adding 1. The calculation for 2024 is as follows:
2024 mod 19 + 1 = 11
11 is our Golden Number. We do a lookup on our computus table and see that 11 is associated with the Paschal full moon date of March 25.
The rule then says that Easter should be observed the next Sunday following this date. If the Paschal full moon date lands on a Sunday, Easter will be observed the following Sunday.
The closest Sunday following March 25, 2024 is March 31, 2024 so that is our date for Easter 2024. Now Google it to check if I’m right.
Now we can determine the date of other holidays dependent on Easter:
- Mardi Gras: 47 days before Easter
- Ash Wednesday: 46 days before Easter
- Palm Sunday: 7 days before Easter
- Good Friday: 2 days before Easter
Enter Holidate
After learning all I did about holiday calculation, especially that of Easter and its related holidays, I decided to publish those algorithms for anyone to use without going through the mess of writing the logic themselves.
You can install the dependency free npm package with
npm i holidate
or you can check out the source code on github.
It has basic features allowing you to query holidays by year, locale, language, and holiday type.
Most of the existing holiday logic is for US-based holidays and available in English and Spanish. If you’d like to help add holidays from other countries or from cultures or religions not currently represented in the holidate library, feel free to open a pull request and contribute to the repo.
Now go forth and automate your holiday lists!
Apply It Elsewhere
This article is about holiday calculation but the idea and process could apply to any date calculation regardless of being a holiday or not. The holidate library is a very basic rule engine. It relies on holidays being defined by rules. The code processes these rules to determine the date of a holiday for a given year. This same process could easily be applied to any type of recurring event.
Need help with your software project?
My day job is working as a software engineer for Trendsic where I help businesses large and small plan and develop software ideas using lean practices. Reach out to me at contact@zachnology.io to discuss how I can help bring your ideas to life.
Top comments (0)