kenya-holidays
Version:
A simple package to retrieve all Kenyan public holidays for a given year
238 lines (212 loc) • 8.78 kB
JavaScript
// File: index.js
/**
* Kenya Public Holidays
* A simple package to get all Kenyan public holidays for a given year
*/
/**
* Calculate Easter Sunday date for a given year
* Based on Butcher's algorithm
* @param {number} year - The year to calculate Easter for
* @return {Date} - Easter Sunday Date object
*/
function calculateEaster(year) {
// Use Meeus/Jones/Butcher algorithm
const a = year % 19;
const b = Math.floor(year / 100);
const c = year % 100;
const d = Math.floor(b / 4);
const e = b % 4;
const f = Math.floor((b + 8) / 25);
const g = Math.floor((b - f + 1) / 3);
const h = (19 * a + b - d - g + 15) % 30;
const i = Math.floor(c / 4);
const k = c % 4;
const l = (32 + 2 * e + 2 * i - h - k) % 7;
const m = Math.floor((a + 11 * h + 22 * l) / 451);
const month = Math.floor((h + l - 7 * m + 114) / 31) - 1; // 0-based month
const day = ((h + l - 7 * m + 114) % 31) + 1;
return new Date(year, month, day);
}
/**
* Get Good Friday date (two days before Easter Sunday)
* @param {number} year - The year to calculate for
* @return {Date} - Good Friday Date object
*/
function getGoodFriday(year) {
const easter = calculateEaster(year);
const goodFriday = new Date(easter);
goodFriday.setDate(easter.getDate() - 2);
return goodFriday;
}
/**
* Format a date in YYYY-MM-DD format
* @param {Date} date - The date to format
* @return {string} - Formatted date string
*/
function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
/**
* Get all Kenyan public holidays for a given year
* @param {number} [year=null] - The year to get holidays for (defaults to current year)
* @param {boolean} [formatted=false] - Whether to return formatted dates (YYYY-MM-DD)
* @return {Object} - Object containing holiday names and their dates
*/
function getKenyanHolidays(year = null, formatted = false) {
// Use current year if not specified
const targetYear = year || new Date().getFullYear();
// Calculate Easter-dependent dates
const easterSunday = calculateEaster(targetYear);
const goodFriday = getGoodFriday(targetYear);
const easterMonday = new Date(easterSunday);
easterMonday.setDate(easterSunday.getDate() + 1);
// Define fixed holidays
const holidays = {
"New Year's Day": new Date(targetYear, 0, 1), // January 1
"Good Friday": goodFriday,
"Easter Monday": easterMonday,
"Labour Day": new Date(targetYear, 4, 1), // May 1
"Madaraka Day": new Date(targetYear, 5, 1), // June 1
"Huduma Day": new Date(targetYear, 9, 10), // October 10
"Mashujaa Day": new Date(targetYear, 9, 20), // October 20
"Jamhuri Day": new Date(targetYear, 11, 12), // December 12
"Christmas Day": new Date(targetYear, 11, 25), // December 25
"Boxing Day": new Date(targetYear, 11, 26), // December 26
"Utamaduni Day": new Date(targetYear, 11, 27), // December 27
};
// Note: Eid holidays are not included as they require Islamic lunar calendar calculations
// Consider adding a note or placeholder for these
holidays["Eid al-Fitr*"] = "Variable date based on Islamic calendar";
holidays["Eid al-Adha*"] = "Variable date based on Islamic calendar";
holidays["Diwali*"] = "Variable date (sometimes declared a public holiday)";
// Format dates if requested
if (formatted) {
const formattedHolidays = {};
for (const [name, date] of Object.entries(holidays)) {
if (date instanceof Date) {
formattedHolidays[name] = formatDate(date);
} else {
formattedHolidays[name] = date; // Keep as is for variable dates
}
}
return formattedHolidays;
}
return holidays;
}
/**
* Get Kenyan holidays in a more detailed format with additional information
* @param {number} [year=null] - The year to get holidays for (defaults to current year)
* @return {Array} - Array of holiday objects with date, name, and type
*/
function getDetailedKenyanHolidays(year = null) {
const targetYear = year || new Date().getFullYear();
const basicHolidays = getKenyanHolidays(targetYear);
const detailedHolidays = [];
// Define holiday types
const holidayTypes = {
"New Year's Day": "National",
"Good Friday": "Religious",
"Easter Monday": "Religious",
"Labour Day": "National",
"Madaraka Day": "National",
"Huduma Day": "National",
"Mashujaa Day": "National",
"Jamhuri Day": "National",
"Christmas Day": "Religious",
"Boxing Day": "National",
"Utamaduni Day": "National",
"Eid al-Fitr*": "Religious",
"Eid al-Adha*": "Religious",
"Diwali*": "Religious"
};
// Add descriptions
const descriptions = {
"New Year's Day": "Celebrates the start of the new year",
"Good Friday": "Commemorates the crucifixion of Jesus Christ",
"Easter Monday": "Celebrates the resurrection of Jesus Christ",
"Labour Day": "Honors the contributions of workers",
"Madaraka Day": "Commemorates Kenya gaining internal self-rule in 1963",
"Huduma Day": "Celebrates public service and national unity",
"Mashujaa Day": "Honors all Kenyans who contributed to the independence struggle",
"Jamhuri Day": "Celebrates Kenya's independence from Britain in 1963",
"Christmas Day": "Celebrates the birth of Jesus Christ",
"Boxing Day": "Traditional day of giving to the less fortunate",
"Utamaduni Day": "Celebrates Kenya's cultural heritage",
"Eid al-Fitr*": "Marks the end of Ramadan, the Islamic holy month of fasting",
"Eid al-Adha*": "Commemorates Ibrahim's willingness to sacrifice his son",
"Diwali*": "Hindu festival of lights"
};
for (const [name, date] of Object.entries(basicHolidays)) {
detailedHolidays.push({
name: name,
date: date instanceof Date ? formatDate(date) : date,
type: holidayTypes[name] || "Other",
description: descriptions[name] || "",
isVariable: !(date instanceof Date)
});
}
// Sort by date (putting variable dates at the end)
return detailedHolidays.sort((a, b) => {
if (a.isVariable && !b.isVariable) return 1;
if (!a.isVariable && b.isVariable) return -1;
if (a.isVariable && b.isVariable) return 0;
return new Date(a.date) - new Date(b.date);
});
}
/**
* Check if a specific date is a Kenyan public holiday
* @param {Date|string} date - The date to check (Date object or YYYY-MM-DD string)
* @param {number} [year=null] - Optional year to use for holiday calculation (defaults to year of provided date)
* @return {Object|null} - Holiday information if it's a holiday, null otherwise
*/
function isKenyanHoliday(date, year = null) {
// Convert string date to Date object if needed
let dateObj;
if (typeof date === 'string') {
dateObj = new Date(date);
} else if (date instanceof Date) {
dateObj = new Date(date);
} else {
throw new Error('Date must be a Date object or a YYYY-MM-DD string');
}
// Use year from date if not specified
const targetYear = year || dateObj.getFullYear();
// Get all holidays for the target year
const holidays = getKenyanHolidays(targetYear);
// Format the input date for comparison (strip time component)
const formattedDate = new Date(
dateObj.getFullYear(),
dateObj.getMonth(),
dateObj.getDate()
);
// Check if the date matches any holiday
for (const [name, holidayDate] of Object.entries(holidays)) {
if (holidayDate instanceof Date) {
const formattedHolidayDate = new Date(
holidayDate.getFullYear(),
holidayDate.getMonth(),
holidayDate.getDate()
);
if (formattedDate.getTime() === formattedHolidayDate.getTime()) {
// Get the detailed info for this holiday
const detailedHolidays = getDetailedKenyanHolidays(targetYear);
const holidayInfo = detailedHolidays.find(h => h.name === name);
return {
name,
date: formatDate(holidayDate),
type: holidayInfo ? holidayInfo.type : null,
description: holidayInfo ? holidayInfo.description : null
};
}
}
}
return null;
}
module.exports = {
getKenyanHolidays,
getDetailedKenyanHolidays,
isKenyanHoliday
};