parsing fixed-date holidays #11

This commit is contained in:
Tomasz Swistak
2024-03-13 20:29:24 +01:00
parent fe9ba44d12
commit a45e170a18
2 changed files with 46 additions and 13 deletions

View File

@@ -79,6 +79,7 @@ export const COUNTRIES = [
export const START_YEAR = new Date().getFullYear(); // start with current year
export const END_YEAR = START_YEAR + 1;
export const FIXED_DATE_START_YEAR = 1970; // start recurring events from start of Unix epoch
// https://www.npmjs.com/package/date-holidays#types-of-holidays
export const TYPE_WHITELIST = ["public", "bank"];

View File

@@ -6,7 +6,7 @@ import { promisify } from "node:util";
import Holidays from "date-holidays";
import { createEvents as icsCreateEvents } from "ics";
import { COUNTRIES, END_YEAR, ICS_PATH, SHOULD_LOG, START_YEAR, TYPE_WHITELIST } from "./config.js";
import { COUNTRIES, END_YEAR, FIXED_DATE_START_YEAR, ICS_PATH, SHOULD_LOG, START_YEAR, TYPE_WHITELIST } from "./config.js";
// converting createEvents from ics from function with callback to async function for easier usage
const createEvents = promisify(icsCreateEvents);
@@ -39,11 +39,12 @@ function getEvents(countryCode) {
* Generates reproducible ID for holiday
* @param {string} countryCode
* @param {string} date
* @param {string} rule
* @returns
*/
function generateUid(countryCode, date) {
function generateUid(countryCode, date, rule) {
const hashGen = createHash("sha256");
hashGen.update(`${countryCode},${date}`);
hashGen.update(`${countryCode},${date},${rule}`);
return hashGen.digest("hex");
}
@@ -56,6 +57,16 @@ function getDateArray(date) {
return [date.getFullYear(), date.getMonth() + 1, date.getDate()];
}
/**
* Checks if holiday is a fixed-date holiday.
* Regex based on https://github.com/commenthol/date-holidays/blob/master/docs/specification.md#fixed-date
* @param {string} rule
* @returns
*/
function isFixedDate(rule) {
return /^\d\d-\d\d$/.test(rule);
}
/**
* Generate ical file from given set of events
* @param {ReturnType<getEvents>} events
@@ -63,16 +74,37 @@ function getDateArray(date) {
* @returns {Promise<string>}
*/
async function generateIcal(events, countryCode) {
const ical = await createEvents(
events.map((x) => ({
title: x.name,
uid: generateUid(countryCode, x.date),
start: getDateArray(x.start),
end: getDateArray(x.end),
productId: "Fossify Calendar Holiday Generator",
status: "CONFIRMED",
}))
);
const eventsMap = new Map();
events.forEach((x) => {
if (isFixedDate(x.rule)) {
const uid = generateUid(countryCode, "", x.rule);
if (!eventsMap.has(uid)) {
const yearDiff = x.end.getFullYear() - x.start.getFullYear();
x.start.setFullYear(FIXED_DATE_START_YEAR);
x.end.setFullYear(FIXED_DATE_START_YEAR + yearDiff);
eventsMap.set(uid, {
title: x.name,
uid,
start: getDateArray(x.start),
end: getDateArray(x.end),
recurrenceRule: "FREQ=YEARLY",
productId: "Fossify Calendar Holiday Generator",
status: "CONFIRMED",
});
}
} else {
const uid = generateUid(countryCode, x.date, x.rule);
eventsMap.set(uid, {
title: x.name,
uid,
start: getDateArray(x.start),
end: getDateArray(x.end),
productId: "Fossify Calendar Holiday Generator",
status: "CONFIRMED",
});
}
});
const ical = await createEvents([...eventsMap.values()]);
return ical;
}