If you build anything for Sri Lanka (payroll, delivery dates, booking slots, a school timetable) you need the holiday list. It can't be computed. The full moon Poya days follow the lunar calendar, other dates move with religious calendars, and the government publishes the list for each year by gazette.
I needed it for my own tools, so I put it in one clean dataset and made it free to use. Here is what's in it, and two mistakes that are easy to make once you start doing date maths with it.
Where the data comes from
The source is the Central Bank of Sri Lanka's published bank-holiday lists for 2026 and 2027. Those follow the holidays gazetted under the Holidays Act, No. 29 of 1971 (the 2027 list is Extraordinary Gazette No. 2493/05). Every row was checked against the Central Bank's table, including the weekday it prints.
2027 has 25 holidays: 12 of them are Poya days and 8 are also mercantile holidays. 2026 has 26, with 13 Poya days.
The files
The repo is HiranthaSandaruwan/sri-lanka-public-holidays. Each holiday looks like this:
{
"date": "2027-01-22",
"weekday": "Friday",
"name": "Duruthu Full Moon Poya Day",
"poya": true,
"mercantile": false,
"bank": true,
"public": true
}
-
poyais true for the Poya day itself, not for "the day following Vesak Poya", which is a separate holiday. -
mercantilemeans it is also a mercantile holiday, the one that applies to private-sector employees. -
bankandpublicare true for every row. Saturdays and Sundays are bank holidays too. A plain weekend isn't listed, but a holiday that falls on one is (2026-01-03, a Poya day, is a Saturday).
There is one file per year (data/holidays-2026.json, data/holidays-2027.json), data/holidays.json with all years, and data/holidays.csv:
date,weekday,name,poya,mercantile,bank,public
2026-01-03,Saturday,Duruthu Full Moon Poya Day,true,false,true,true
2026-01-15,Thursday,Tamil Thai Pongal Day,false,true,true,true
The calendars folder has the same list as three .ics files (every holiday, Poya days only, mercantile holidays only). They are all-day events marked as free time, so importing one into a calendar app won't make you look busy.
Reading it straight from GitHub:
const url = "https://raw.githubusercontent.com/HiranthaSandaruwan/sri-lanka-public-holidays/main/data/holidays-2027.json";
const holidays = await (await fetch(url)).json();
const offDays = new Set(holidays.map((h) => h.date));
const isHoliday = (iso) => offDays.has(iso);
A Set of dates is better than counting rows, because two holidays can share a day. On 2026-05-01, Vesak Full Moon Poya Day and May Day fall together, so 2026 has 26 rows but 25 different dates.
Bug 1: "today" in UTC is the wrong day
Sri Lanka is UTC+5:30 all year, with no daylight saving. A server running in UTC that does new Date().toISOString().slice(0, 10) gets the UTC date, which is still yesterday between midnight and 05:30 in Colombo.
That is enough to get a holiday wrong. At 01:30 on 24 November 2026 in Colombo, it is 20:00 on the 23rd in UTC. The 24th is Il Full Moon Poya Day, so the server would say "tomorrow is a holiday" on the holiday itself. Ask for the date in Sri Lanka's time zone instead:
const todayInColombo = () =>
new Intl.DateTimeFormat("en-CA", { timeZone: "Asia/Colombo" }).format(new Date());
// The files are sorted by date, and ISO dates compare correctly as plain strings.
const next = holidays.find((h) => h.date >= todayInColombo());
The en-CA locale formats a date as YYYY-MM-DD, the same shape as the date field.
Bug 2: counting working days
A common question is how many working days fall between two dates. Walk the days, skip Saturdays, Sundays and holidays, and do the walking in UTC:
const DAY = 86_400_000;
const utc = (iso) => Date.parse(`${iso}T00:00:00Z`);
function workingDays(start, end, holidays) {
const off = new Set(holidays.map((h) => h.date));
let n = 0;
for (let t = utc(start); t <= utc(end); t += DAY) {
const d = new Date(t);
const weekend = d.getUTCDay() === 0 || d.getUTCDay() === 6;
if (!weekend && !off.has(d.toISOString().slice(0, 10))) n++;
}
return n;
}
workingDays("2027-04-01", "2027-04-30", holidays); // 19
workingDays("2027-04-01", "2027-04-30", holidays.filter((h) => h.mercantile)); // 20
Why UTC, when Sri Lanka has no daylight saving? Because the machine running the code might. If you build local dates with new Date(2027, 3, 1) and add 24 hours at a time, a clock change in the server's own time zone can push one step to 23:00 on the day before, and a date gets counted twice or skipped. UTC midnights never move.
The two answers differ because of who you count for. April 2027 has three holidays on weekdays: the day before the Sinhala and Tamil New Year (Tuesday 13th), New Year Day itself (Wednesday 14th) and Bak Full Moon Poya Day (Tuesday 20th). Bak Poya is a public and bank holiday but not a mercantile one, so for private-sector staff the month has one working day more. If you build payroll or leave tools, filter on mercantile rather than using every row.
Licence
The dataset is CC BY 4.0: use it for anything, including commercial work, with a credit link. The government can still amend the list by notification, so check the Sri Lanka holidays page before relying on a date months ahead.
If you spot a wrong date, open an issue on the repo. Which other Sri Lankan data would you like to have as a clean file like this?
This article was written with the help of AI. The code, numbers and sources come from my own project and were checked against it before publishing.
Top comments (0)