/** * Holiday detection service to provide hints for upcoming celebrations. */ interface Holiday { name: string; month: number; // 0-indexed (0 = Jan, 11 = Dec) day: number; description: string; } // Fixed-date holidays const FIXED_HOLIDAYS: Holiday[] = [ { name: 'New Year\'s Day', month: 0, day: 1, description: 'Happy New Year!' }, { name: 'Valentine\'s Day', month: 1, day: 14, description: 'Love is in the air!' }, { name: 'Halloween', month: 9, day: 31, description: 'Trick or treat!' }, { name: 'Armistice Day', month: 10, day: 11, description: 'Lest we forget.' }, // Remembrance Day { name: 'Christmas Eve', month: 11, day: 24, description: 'Twas the night before Christmas...' }, { name: 'Christmas Day', month: 11, day: 25, description: 'Merry Christmas!' }, { name: 'Boxing Day', month: 11, day: 26, description: 'Happy Boxing Day!' }, { name: 'New Year\'s Eve', month: 11, day: 31, description: 'Ring in the New Year!' }, ]; /** * Calculates Easter Sunday for a given year using the Meeus/Jones/Butcher algorithm. */ function getEasterSunday(year: number): Date { 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); } /** * Returns a hint if there is a major holiday or celebration in the week starting from weekStart. * A "week" is defined as 7 days from weekStart. */ export function getHolidayHint(weekStart: Date): string | null { const weekEnd = new Date(weekStart); weekEnd.setDate(weekEnd.getDate() + 7); const year = weekStart.getFullYear(); // Check fixed holidays for (const holiday of FIXED_HOLIDAYS) { // Handle year boundaries for fixed holidays (e.g. looking at Jan 1 from Dec 28) const yearsToCheck = [year, year + 1]; for (const y of yearsToCheck) { const holidayDate = new Date(y, holiday.month, holiday.day); if (holidayDate >= weekStart && holidayDate < weekEnd) { return `Hint: ${holiday.name} is coming up! ${holiday.description}`; } } } // Check variable holidays (Easter related) const easter = getEasterSunday(year); // Easter Sunday if (easter >= weekStart && easter < weekEnd) { return "Hint: Easter Sunday is this week! Happy Easter!"; } // Good Friday (2 days before) const goodFriday = new Date(easter); goodFriday.setDate(goodFriday.getDate() - 2); if (goodFriday >= weekStart && goodFriday < weekEnd) { return "Hint: Good Friday is this week."; } // Easter Monday (1 day after) const easterMonday = new Date(easter); easterMonday.setDate(easterMonday.getDate() + 1); if (easterMonday >= weekStart && easterMonday < weekEnd) { return "Hint: Easter Monday is this week."; } return null; }