From b3fb346509d2b43352b925bb3ce4385a9cf26500 Mon Sep 17 00:00:00 2001 From: Zachary Date: Sun, 10 Nov 2024 21:34:28 +0100 Subject: [PATCH] Add fixed data for every country from wikipedia --- src/lib/holidayUtils.js | 143 ++++++++++ src/lib/ptoData.js | 580 ++++++++++++++++++++++++++++++++++++++++ src/routes/+page.svelte | 4 +- 3 files changed, 726 insertions(+), 1 deletion(-) create mode 100644 src/lib/holidayUtils.js create mode 100644 src/lib/ptoData.js diff --git a/src/lib/holidayUtils.js b/src/lib/holidayUtils.js new file mode 100644 index 0000000..b73fcb3 --- /dev/null +++ b/src/lib/holidayUtils.js @@ -0,0 +1,143 @@ +import Holidays from 'date-holidays'; + +// getHolidaysForYear(countryCode: string, year: number): { date: Date, name: string }[] +export function getHolidaysForYear(countryCode, year) { + const hd = new Holidays(countryCode); + return hd.getHolidays(year) + .filter(holiday => holiday.type === 'public') + .map(holiday => ({ + date: new Date(holiday.date), + name: holiday.name + })); +} + +// optimizeDaysOff(holidays: { date: Date, name: string }[], year: number, daysOff: number): Date[] +export function optimizeDaysOff(holidays, year, daysOff) { + const weekends = getWeekends(year); + const allDaysOff = [...holidays.map(h => h.date), ...weekends]; + allDaysOff.sort((a, b) => a - b); + + const gaps = findGaps(allDaysOff, year); + const rankedGaps = rankGapsByEfficiency(gaps); + + return selectDaysOff(rankedGaps, daysOff, allDaysOff); +} + +// calculateConsecutiveDaysOff(holidays: { date: Date, name: string }[], optimizedDaysOff: Date[], year: number): { startDate: string, endDate: string, includesHoliday: boolean, message: string }[] +export function calculateConsecutiveDaysOff(holidays, optimizedDaysOff, year) { + let consecutiveDaysOff = []; + const allDays = [...holidays.map(h => h.date), ...optimizedDaysOff]; + allDays.sort((a, b) => a - b); + + let currentGroup = []; + let includesHoliday = false; + + for (let month = 0; month < 12; month++) { + for (let day = 1; day <= 31; day++) { + const date = new Date(year, month, day); + if (date.getMonth() !== month) break; + + const isWeekend = date.getDay() === 0 || date.getDay() === 6; + const isHoliday = holidays.some(h => h.date.getTime() === date.getTime()); + const isDayOff = optimizedDaysOff.some(d => d.getTime() === date.getTime()); + + if (isWeekend || isHoliday || isDayOff) { + currentGroup.push(date); + if (isHoliday) includesHoliday = true; + } else if (currentGroup.length > 0) { + if (currentGroup.some(d => optimizedDaysOff.some(od => od.getTime() === d.getTime()))) { + const startDate = currentGroup[0]; + const endDate = currentGroup[currentGroup.length - 1]; + const totalDays = Math.round((endDate - startDate) / (1000 * 60 * 60 * 24) + 1); + const usedDaysOff = currentGroup.filter(d => optimizedDaysOff.some(od => od.getTime() === d.getTime())).length; + const message = `${usedDaysOff} days off -> ${totalDays} days`; + + consecutiveDaysOff.push({ + startDate: formatDate(startDate), + endDate: formatDate(endDate), + includesHoliday, + message + }); + } + currentGroup = []; + includesHoliday = false; + } + } + } + + if (currentGroup.length > 0 && currentGroup.some(d => optimizedDaysOff.some(od => od.getTime() === d.getTime()))) { + const startDate = currentGroup[0]; + const endDate = currentGroup[currentGroup.length - 1]; + const totalDays = Math.round((endDate - startDate) / (1000 * 60 * 60 * 24) + 1); + const usedDaysOff = currentGroup.filter(d => optimizedDaysOff.some(od => od.getTime() === d.getTime())).length; + const message = `${usedDaysOff} day off turns into ${totalDays} days off`; + + consecutiveDaysOff.push({ + startDate: formatDate(startDate), + endDate: formatDate(endDate), + includesHoliday, + message + }); + } + + return consecutiveDaysOff; +} + +function getWeekends(year) { + const weekends = []; + for (let month = 0; month < 12; month++) { + for (let day = 1; day <= 31; day++) { + const date = new Date(year, month, day); + if (date.getMonth() !== month) break; + if (date.getDay() === 0 || date.getDay() === 6) { + weekends.push(date); + } + } + } + return weekends; +} + +function findGaps(allDaysOff, year) { + const gaps = []; + for (let i = 0; i < allDaysOff.length - 1; i++) { + const start = allDaysOff[i]; + const end = allDaysOff[i + 1]; + const gapLength = (end - start) / (1000 * 60 * 60 * 24) - 1; + if (gapLength > 0 && gapLength <= 4) { + gaps.push({ start, end, gapLength }); + } + } + return gaps; +} + +function rankGapsByEfficiency(gaps) { + return gaps.map(gap => { + const potentialChainLength = gap.gapLength + 2; // including weekends/holidays + const efficiency = potentialChainLength / gap.gapLength; + return { ...gap, potentialChainLength, efficiency }; + }).sort((a, b) => b.efficiency - a.efficiency); +} + +function selectDaysOff(rankedGaps, daysOff, allDaysOff) { + const selectedDays = []; + const allDaysOffSet = new Set(allDaysOff.map(date => date.getTime())); + + for (const gap of rankedGaps) { + for (let i = 1; i <= gap.gapLength && daysOff > 0; i++) { + const potentialDayOff = new Date(gap.start); + potentialDayOff.setDate(potentialDayOff.getDate() + i); + + // Ensure the day is not a weekend or holiday + if (!allDaysOffSet.has(potentialDayOff.getTime()) && potentialDayOff.getDay() !== 0 && potentialDayOff.getDay() !== 6) { + selectedDays.push(potentialDayOff); + daysOff--; + } + } + if (daysOff <= 0) break; + } + return selectedDays; +} + +function formatDate(date) { + return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); +} \ No newline at end of file diff --git a/src/lib/ptoData.js b/src/lib/ptoData.js new file mode 100644 index 0000000..767f14a --- /dev/null +++ b/src/lib/ptoData.js @@ -0,0 +1,580 @@ +export const ptoData = { + // Afghanistan + AF: 20, // 20 days recreational leave, 15 paid public holidays + + // Albania + AL: 28, // 28 days of annual leave, 12 paid public holidays + + // Algeria + DZ: 30, // 30 calendar days per year, 11 paid public holidays + + // Andorra + AD: 31, // 31 calendar days, 14 paid public holidays + + // Angola + AO: 22, // 22 days, 11 paid public holidays + + // Antigua and Barbuda + AG: 12, // 12 days per year, 11 paid public holidays + + // Argentina + AR: 10, // 10 working days (0-5 years), 15 paid public holidays + + // Armenia + AM: 20, // 20 working days, 12 paid public holidays + + // Australia + AU: 20, // 4 weeks, 10-13 paid public holidays depending on state + + // Austria + AT: 25, // 25 days (less than 25 years of service), 13 paid public holidays + + // Azerbaijan + AZ: 21, // 21 basic calendar days, 19 paid public holidays + + // The Bahamas + BS: 10, // 14 days after 1 year, 10 paid public holidays + + // Bahrain + BH: 30, // 30 days, 14 paid public holidays + + // Bangladesh + BD: 10, // 10 days casual leave, 11 paid public holidays + + // Barbados + BB: 15, // 3 weeks (less than 5 years), no public holidays listed + + // Belarus + BY: 24, // 24 calendar days, 9 paid public holidays + + // Belgium + BE: 20, // 20 working days, 10 paid public holidays + + // Belize + BZ: 14, // 2 weeks, 13 paid public holidays + + // Benin + BJ: 24, // 2 working days per month, 13 paid public holidays + + // Bhutan + BT: 9, // No specific data on annual leave, 9 public holidays + + // Bolivia + BO: 15, // 15 working days (1-5 years), 11 paid public holidays + + // Bosnia and Herzegovina + BA: 20, // 20 working days, 9-11 paid public holidays + + // Botswana + BW: 15, // 1.25 days per month, 14 paid public holidays + + // Brazil + BR: 10, // 10 working days (absent 24-32 days), 13 paid public holidays + + // Brunei Darussalam + BN: 7, // 7 days, 11 paid public holidays + + // Bulgaria + BG: 20, // 4 weeks, 12 paid public holidays + + // Burkina Faso + BF: 30, // 2.5 calendar days per month, 15 paid public holidays + + // Burundi + BI: 17, // 1 and 2/3 working days per month, 13 paid public holidays + + // Cape Verde + CV: 22, // 22 days, no public holidays listed + + // Cambodia + KH: 18, // 1.5 work days per month, 27 paid public holidays + + // Cameroon + CM: 18, // 1.5 days per month, no public holidays listed + + // Canada + CA: 10, // 2 weeks, 7-13 paid public holidays depending on province + + // Central African Republic + CF: 24, // 2 working days per month, no public holidays listed + + // Chad + TD: 24, // 2 days per month, 3 paid public holidays + + // Chile + CL: 15, // 15 working days, 15 paid public holidays + + // China + CN: 5, // 5 days (1-10 years), 11 paid public holidays + + // Colombia + CO: 15, // 15 consecutive working days, 18 paid public holidays + + // Comoros + KM: 25, // 2.5 days per month, no public holidays listed + + // Democratic Republic of Congo + CD: 12, // 1 day per month, no public holidays listed + + // Republic of Congo + CG: 26, // 26 working days, no public holidays listed + + // Costa Rica + CR: 10, // 2 weeks, 9 paid public holidays + + // Croatia + HR: 20, // 4 weeks, 13 paid public holidays + + // Cuba + CU: 22, // 1 month, 9 paid public holidays + + // Cyprus + CY: 20, // 20 working days, 14 paid public holidays + + // Czech Republic + CZ: 20, // 4 weeks, 13 paid public holidays + + // Denmark + DK: 25, // 25 days, 10 paid public holidays + + // Djibouti + DJ: 25, // 2.5 working days per month, 10 paid public holidays + + // Dominica + DM: 10, // 2 weeks, 12 paid public holidays + + // Dominican Republic + DO: 10, // 2 weeks, 13 paid public holidays + + // Ecuador + EC: 11, // 15 consecutive days, 12 paid public holidays + + // Egypt + EG: 21, // 21 days, 17 paid public holidays + + // El Salvador + SV: 15, // 15 days, 11 paid public holidays + + // Equatorial Guinea + GQ: 30, // 1 month, no public holidays listed + + // Eritrea + ER: 12, // 14 working days, no public holidays listed + + // Estonia + EE: 28, // 28 calendar days, 12 paid public holidays + + // Ethiopia + ET: 12, // 14 working days, 13 paid public holidays + + // European Union + EU: 20, // 4 weeks, no public holidays listed + + // Fiji + FJ: 10, // 10 days, 12 paid public holidays + + // Finland + FI: 25, // 5 weeks, 11 paid public holidays + + // France + FR: 25, // 5 weeks, 11 paid public holidays + + // Gabon + GA: 20, // 2 days per month, 14 paid public holidays + + // Gambia + GM: 21, // No specific data on public holidays + + // Georgia + GE: 24, // 24 days, 15 paid public holidays + + // Germany + DE: 20, // 20 working days, 10-13 paid public holidays + + // Ghana + GH: 15, // 15 working days, 13 paid public holidays + + // Greece + GR: 20, // 20 working days, 9 paid public holidays + + // Grenada + GD: 10, // 2 weeks, 13 paid public holidays + + // Guatemala + GT: 15, // 15 working days, 10 paid public holidays + + // Guinea + GN: 22, // 2.5 days per month, 11 paid public holidays + + // Guinea-Bissau + GW: 22, // 30 consecutive days, no public holidays listed + + // Guyana + GY: 12, // 1 day per month, no public holidays listed + + // Haiti + HT: 11, // 15 consecutive days, 16 paid public holidays + + // Honduras + HN: 8, // 10 working days, 11 paid public holidays + + // Hong Kong SAR + HK: 7, // 7 days (1-2 years), 17 paid public holidays + + // Hungary + HU: 20, // 20 working days, 13 paid public holidays + + // Iceland + IS: 24, // 24 working days, 12 paid public holidays + + // India + IN: 25, // 18 vacation days, 10-15 paid public holidays + + // Indonesia + ID: 12, // 12 days, 18 paid public holidays + + // Iran + IR: 26, // 1 month, 27 paid public holidays + + // Iraq + IQ: 20, // 20 days, no public holidays listed + + // Ireland + IE: 20, // 4 weeks, 10 paid public holidays + + // Israel + IL: 12, // 12 days, 9 paid public holidays + + // Italy + IT: 20, // 20 working days, 12 paid public holidays + + // Ivory Coast + CI: 20, // 2 days per month, 14 paid public holidays + + // Jamaica + JM: 10, // 10 days, no public holidays listed + + // Japan + JP: 10, // 10 days, no public holidays listed + + // Jersey + JE: 10, // 2 weeks, 9 paid public holidays + + // Jordan + JO: 14, // 14 days, 10-14 paid public holidays + + // Kazakhstan + KZ: 24, // 24 calendar days, 16 paid public holidays + + // Kenya + KE: 21, // 21 working days, 10 paid public holidays + + // Kiribati + KI: 0, // No specific data on annual leave + + // Kosovo + XK: 20, // 20 days, 12 paid public holidays + + // Kuwait + KW: 30, // 30 days, 13 paid public holidays + + // Kyrgyzstan + KG: 20, // 20 days, no public holidays listed + + // Laos + LA: 15, // 15 days, no public holidays listed + + // Latvia + LV: 20, // 4 calendar weeks, 12 paid public holidays + + // Lebanon + LB: 15, // 15 days, 22 paid public holidays + + // Lesotho + LS: 12, // 12 days, 10 paid public holidays + + // Liberia + LR: 10, // 10 days, 11 paid public holidays + + // Libya + LY: 22, // 30 days, no public holidays listed + + // Lithuania + LT: 20, // 20 working days, 14 paid public holidays + + // Luxembourg + LU: 26, // 26 working days, 11 paid public holidays + + // Madagascar + MG: 22, // 2.5 days per month, 13 paid public holidays + + // Malawi + MW: 18, // No specific data on public holidays + + // Malaysia + MY: 8, // 8 days (first 2 years), 11-16 paid public holidays + + // Maldives + MV: 22, // 22 days, no public holidays listed + + // Mali + ML: 22, // 22 days, no public holidays listed + + // Malta + MT: 27, // 5 weeks and 1 day, 14 paid public holidays + + // Marshall Islands + MH: 0, // No specific data on annual leave + + // Mauritania + MR: 15, // 1.5 days per month, 7 paid public holidays + + // Mauritius + MU: 22, // 20 working days, 16 paid public holidays + + // Mexico + MX: 6, // 6 days (first year), 7-14 paid public holidays + + // Micronesia + FM: 0, // No specific data on annual leave + + // Moldova + MD: 28, // 28 calendar days, 11 paid public holidays + + // Monaco + MC: 30, // 30 days, 12 paid public holidays + + // Mongolia + MN: 15, // 15 days, 9 paid public holidays + + // Montenegro + ME: 20, // 20 working days, 9 paid public holidays + + // Morocco + MA: 18, // 18 days, 14 paid public holidays + + // Mozambique + MZ: 12, // 12 days, 9 paid public holidays + + // Myanmar + MM: 10, // 10 days, 21 paid public holidays + + // Namibia + NA: 24, // 24 days, 12 paid public holidays + + // Nauru + NR: 0, // No specific data on annual leave + + // Nepal + NP: 13, // 13 days, 15 paid public holidays + + // Netherlands + NL: 20, // 20 days, 11 paid public holidays + + // New Zealand + NZ: 20, // 4 weeks, 11 paid public holidays + + // Nicaragua + NI: 15, // 15 days, 9 paid public holidays + + // Niger + NE: 30, // 30 days, 12 paid public holidays + + // Nigeria + NG: 6, // 6 days, 11 paid public holidays + + // North Korea + KP: 15, // 15 days, 17 paid public holidays + + // North Macedonia + MK: 20, // 20 working days, 11 paid public holidays + + // Norway + NO: 25, // 25 days, 10 paid public holidays + + // Oman + OM: 30, // 30 days, 14 paid public holidays + + // Pakistan + PK: 14, // 14 days, 14 paid public holidays + + // Palau + PW: 0, // No specific data on annual leave + + // Panama + PA: 30, // 30 days, 11 paid public holidays + + // Papua New Guinea + PG: 10, // 10 days, 9 paid public holidays + + // Paraguay + PY: 12, // 12 days, 12 paid public holidays + + // Peru + PE: 30, // 30 days, 12 paid public holidays + + // Philippines + PH: 5, // 5 days, 12 paid public holidays + + // Poland + PL: 20, // 20 working days, 13 paid public holidays + + // Portugal + PT: 22, // 22 working days, 13 paid public holidays + + // Qatar + QA: 30, // 30 days, 11 paid public holidays + + // Romania + RO: 20, // 20 working days, 15 paid public holidays + + // Russia + RU: 20, // 28 calendar days, 14 paid public holidays + + // Rwanda + RW: 15, // 1.5 days per month, 11 paid public holidays + + // Saint Kitts and Nevis + KN: 12, // 14 days, no public holidays listed + + // Saint Lucia + LC: 14, // 14 working days, 13 paid public holidays + + // Saint Vincent and the Grenadines + VC: 16, // 16 days, no public holidays listed + + // Samoa + WS: 10, // 10 days, 11 paid public holidays + + // San Marino + SM: 10, // 10 days, no public holidays listed + + // Saudi Arabia + SA: 21, // 21 days, 9 paid public holidays + + // Senegal + SN: 20, // 2 days per month, 12 paid public holidays + + // Serbia + RS: 20, // 20 working days, 11 paid public holidays + + // Seychelles + SC: 21, // 21 days, 13 paid public holidays + + // Sierra Leone + SL: 18, // No specific data on public holidays + + // Singapore + SG: 7, // 7 days (first year), 11 paid public holidays + + // Slovakia + SK: 20, // 4 weeks, 14 paid public holidays + + // Slovenia + SI: 20, // 4 weeks, 13 paid public holidays + + // Solomon Islands + SB: 15, // 1.25 days per month, no public holidays listed + + // Somalia + SO: 13, // 15 days, 9 paid public holidays + + // South Africa + ZA: 15, // 21 consecutive days, 12 paid public holidays + + // South Korea + KR: 15, // 15 days, 15 paid public holidays + + // South Sudan + SS: 20, // 20 days, 12 paid public holidays + + // Spain + ES: 22, // 22 working days, 14 paid public holidays + + // Sri Lanka + LK: 20, // 20 days, 20 paid public holidays + + // Sudan + SD: 20, // 20 days, no public holidays listed + + // Suriname + SR: 12, // 12 days, 18 paid public holidays + + // Swaziland + SZ: 10, // 2 weeks, no public holidays listed + + // Sweden + SE: 25, // 25 work days, 9 paid public holidays + + // Switzerland + CH: 20, // 4 weeks, 7-15 paid public holidays + + // Syria + SY: 24, // 24 working days, 13 paid public holidays + + // Taiwan + TW: 3, // 3 days (half year to 1 year), 12 paid public holidays + + // Tanzania + TZ: 20, // 28 consecutive days, 17 paid public holidays + + // Thailand + TH: 6, // 6 working days, 13 paid public holidays + + // East Timor + TL: 12, // 12 days, no public holidays listed + + // Togo + TG: 22, // 2.5 days per month, no public holidays listed + + // Tonga + TO: 20, // 20 days, no public holidays listed + + // Trinidad and Tobago + TT: 10, // 14 consecutive days, 14 paid public holidays + + // Tunisia + TN: 10, // 1 day per month, 6 paid public holidays + + // Turkey + TR: 12, // 14 work days, 14.5 paid public holidays + + // Uganda + UG: 15, // 7 days per 4 months, 13 paid public holidays + + // Ukraine + UA: 24, // 24 calendar days, 13 paid public holidays + + // United Arab Emirates + AE: 30, // 30 days, 14 paid public holidays + + // United Kingdom + GB: 20, // 28 total working days, 8-10 paid public holidays + + // United States + US: 0, // No federal or state statutory minimum + + // Uruguay + UY: 20, // 20 days, 5 paid public holidays + + // Uzbekistan + UZ: 15, // 15 days, no public holidays listed + + // Vanuatu + VU: 15, // 1.25 days per month, no public holidays listed + + // Venezuela + VE: 15, // 15 days, 14 paid public holidays + + // Vietnam + VN: 12, // 12 days, 11 paid public holidays + + // Yemen + YE: 22, // 30 days, 15 paid public holidays + + // Zambia + ZM: 20, // 2 days per month, 11 paid public holidays + + // Zimbabwe + ZW: 22, // 22 days, 11 paid public holidays +}; \ No newline at end of file diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 604fa29..365ff72 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -4,6 +4,7 @@ import enLocale from 'i18n-iso-countries/langs/en.json'; import CalendarMonth from '../lib/CalendarMonth.svelte'; import { getHolidaysForYear, optimizeDaysOff, calculateConsecutiveDaysOff } from '../lib/holidayUtils.js'; + import { ptoData } from '../lib/ptoData.js'; countries.registerLocale(enLocale); let countriesList = countries.getNames('en'); @@ -12,7 +13,7 @@ let months = Array.from({ length: 12 }, (_, i) => i); let selectedCountry = 'Belgium'; let holidays = []; - let daysOff = 24; + let daysOff = ptoData['BE']; let optimizedDaysOff = []; let consecutiveDaysOff = []; @@ -26,6 +27,7 @@ const countryCode = Object.keys(countriesList).find(code => countriesList[code] === countryName); if (countryCode) { selectedCountry = countryName; + daysOff = ptoData[countryCode] || 0; updateHolidays(); } }