跳到正文
DEV Community· Hirantha Sandaruwan Lakshan·· 4 小時前AI 評分37

斯里蘭卡公眾假期及 Poya 日開放數據:兩個應避免的日期錯誤

Sri Lankan public holidays and Poya days as open data, and two date bugs to avoid

AI 導讀

作者將斯里蘭卡 2026、2027 年公眾假期及 Poya 日整理成免費數據集,並指出日期運算中兩個容易犯的錯誤。2026 年有 26 個假期,包括 13 個 Poya 日;2027 年有 25 個假期,包括 12 個 Poya 日。文章提醒,判斷當日日期應使用斯里蘭卡時區,而計算工作日則應以 UTC 遍歷日期,並按 mercantile 欄位篩選私營機構適用假期。

正文

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
}
  • poya is true for the Poya day itself, not for "the day following Vesak Poya", which is a separate holiday.
  • mercantile means it is also a mercantile holiday, the one that applies to private-sector employees.
  • bank and public are 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.

來源:DEV Community · dev.to