169 lines
5.7 KiB
JavaScript
169 lines
5.7 KiB
JavaScript
/**
|
|
* Holiday Functions
|
|
* German public holidays calculation and checking
|
|
*/
|
|
|
|
/**
|
|
* Check if date is weekend
|
|
*/
|
|
function isWeekend(date) {
|
|
const day = date.getDay();
|
|
return day === 0 || day === 6; // Sunday or Saturday
|
|
}
|
|
|
|
/**
|
|
* Calculate Easter Sunday for a given year (Gauss algorithm)
|
|
*/
|
|
function getEasterSunday(year) {
|
|
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);
|
|
const day = ((h + l - 7 * m + 114) % 31) + 1;
|
|
return new Date(year, month - 1, day);
|
|
}
|
|
|
|
/**
|
|
* Get all public holidays for a given year and Bundesland
|
|
*/
|
|
function getPublicHolidays(year, bundesland) {
|
|
const holidays = [];
|
|
|
|
// Fixed holidays (all states)
|
|
holidays.push({ date: new Date(year, 0, 1), name: 'Neujahr' });
|
|
holidays.push({ date: new Date(year, 4, 1), name: 'Tag der Arbeit' });
|
|
holidays.push({ date: new Date(year, 9, 3), name: 'Tag der Deutschen Einheit' });
|
|
holidays.push({ date: new Date(year, 11, 25), name: '1. Weihnachtstag' });
|
|
holidays.push({ date: new Date(year, 11, 26), name: '2. Weihnachtstag' });
|
|
|
|
// Company-provided holiday: Christmas Eve (24.12) or New Year's Eve (31.12)
|
|
// Default to Christmas if companyHolidayPreference is not defined
|
|
const companyHolidayPref = typeof companyHolidayPreference !== 'undefined' ? companyHolidayPreference : 'christmas';
|
|
if (companyHolidayPref === 'christmas') {
|
|
holidays.push({ date: new Date(year, 11, 24), name: 'Heiligabend (Betriebsfrei)' });
|
|
} else if (companyHolidayPref === 'newyearseve') {
|
|
holidays.push({ date: new Date(year, 11, 31), name: 'Silvester (Betriebsfrei)' });
|
|
}
|
|
|
|
// Heilige Drei Könige (BW, BY, ST)
|
|
if (['BW', 'BY', 'ST'].includes(bundesland)) {
|
|
holidays.push({ date: new Date(year, 0, 6), name: 'Heilige Drei Könige' });
|
|
}
|
|
|
|
// Internationaler Frauentag (BE, MV since 2023)
|
|
if (['BE'].includes(bundesland) || (bundesland === 'MV' && year >= 2023)) {
|
|
holidays.push({ date: new Date(year, 2, 8), name: 'Internationaler Frauentag' });
|
|
}
|
|
|
|
// Weltkindertag (TH since 2019)
|
|
if (bundesland === 'TH' && year >= 2019) {
|
|
holidays.push({ date: new Date(year, 8, 20), name: 'Weltkindertag' });
|
|
}
|
|
|
|
// Reformationstag (BB, MV, SN, ST, TH, + HB, HH, NI, SH since 2018)
|
|
const reformationstagStates = ['BB', 'MV', 'SN', 'ST', 'TH'];
|
|
if (year >= 2018) {
|
|
reformationstagStates.push('HB', 'HH', 'NI', 'SH');
|
|
}
|
|
if (reformationstagStates.includes(bundesland)) {
|
|
holidays.push({ date: new Date(year, 9, 31), name: 'Reformationstag' });
|
|
}
|
|
|
|
// Allerheiligen (BW, BY, NW, RP, SL)
|
|
if (['BW', 'BY', 'NW', 'RP', 'SL'].includes(bundesland)) {
|
|
holidays.push({ date: new Date(year, 10, 1), name: 'Allerheiligen' });
|
|
}
|
|
|
|
// Buß- und Bettag (only SN)
|
|
if (bundesland === 'SN') {
|
|
// Buß- und Bettag is the Wednesday before November 23
|
|
let bussbettag = new Date(year, 10, 23);
|
|
while (bussbettag.getDay() !== 3) { // 3 = Wednesday
|
|
bussbettag.setDate(bussbettag.getDate() - 1);
|
|
}
|
|
bussbettag.setDate(bussbettag.getDate() - 7); // One week before
|
|
holidays.push({ date: bussbettag, name: 'Buß- und Bettag' });
|
|
}
|
|
|
|
// Easter-dependent holidays
|
|
const easter = getEasterSunday(year);
|
|
|
|
// Karfreitag (Good Friday) - 2 days before Easter (all states)
|
|
const goodFriday = new Date(easter);
|
|
goodFriday.setDate(easter.getDate() - 2);
|
|
holidays.push({ date: goodFriday, name: 'Karfreitag' });
|
|
|
|
// Ostermontag (Easter Monday) - 1 day after Easter (all states)
|
|
const easterMonday = new Date(easter);
|
|
easterMonday.setDate(easter.getDate() + 1);
|
|
holidays.push({ date: easterMonday, name: 'Ostermontag' });
|
|
|
|
// Christi Himmelfahrt (Ascension Day) - 39 days after Easter (all states)
|
|
const ascension = new Date(easter);
|
|
ascension.setDate(easter.getDate() + 39);
|
|
holidays.push({ date: ascension, name: 'Christi Himmelfahrt' });
|
|
|
|
// Pfingstmontag (Whit Monday) - 50 days after Easter (all states)
|
|
const whitMonday = new Date(easter);
|
|
whitMonday.setDate(easter.getDate() + 50);
|
|
holidays.push({ date: whitMonday, name: 'Pfingstmontag' });
|
|
|
|
// Fronleichnam (Corpus Christi) - 60 days after Easter (BW, BY, HE, NW, RP, SL, + some communities in SN, TH)
|
|
if (['BW', 'BY', 'HE', 'NW', 'RP', 'SL'].includes(bundesland)) {
|
|
const corpusChristi = new Date(easter);
|
|
corpusChristi.setDate(easter.getDate() + 60);
|
|
holidays.push({ date: corpusChristi, name: 'Fronleichnam' });
|
|
}
|
|
|
|
// Mariä Himmelfahrt (Assumption of Mary) - August 15 (BY in some communities, SL)
|
|
if (['SL'].includes(bundesland)) {
|
|
holidays.push({ date: new Date(year, 7, 15), name: 'Mariä Himmelfahrt' });
|
|
}
|
|
|
|
return holidays;
|
|
}
|
|
|
|
/**
|
|
* Check if date is a public holiday
|
|
* Returns the holiday name or null
|
|
*/
|
|
function getHolidayName(date) {
|
|
const year = date.getFullYear();
|
|
const month = date.getMonth();
|
|
const day = date.getDate();
|
|
|
|
const holidays = getPublicHolidays(year, currentBundesland);
|
|
|
|
// Compare year, month, and day directly (avoid timezone issues)
|
|
const holiday = holidays.find(h => {
|
|
return h.date.getFullYear() === year &&
|
|
h.date.getMonth() === month &&
|
|
h.date.getDate() === day;
|
|
});
|
|
|
|
return holiday ? holiday.name : null;
|
|
}
|
|
|
|
/**
|
|
* Check if date is a public holiday
|
|
*/
|
|
function isPublicHoliday(date) {
|
|
return getHolidayName(date) !== null;
|
|
}
|
|
|
|
/**
|
|
* Check if date is weekend or public holiday
|
|
*/
|
|
function isWeekendOrHoliday(date) {
|
|
return isWeekend(date) || isPublicHoliday(date);
|
|
}
|