calculate_working_days_eu
Calculate the number of working days between two dates for a European country, excluding weekends and national holidays. Supports PT, ES, FR, DE, IT, NL, BE, UK.
Instructions
Counts the number of working days between two dates (inclusive) for a given European country, excluding weekends and that country's national public holidays. Returns { country, start_date, end_date, working_days, holidays_excluded }. Supports PT, ES, FR, DE, IT, NL, BE, UK. Use when calculating cross-border SLA periods, invoice payment deadlines, or project timelines that must account for different national holiday calendars.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| country_code | Yes | Two-letter ISO country code. Example: 'DE', 'IT', 'UK' | |
| start_date | Yes | Start date in YYYY-MM-DD format, inclusive. Example: '2026-01-01' | |
| end_date | Yes | End date in YYYY-MM-DD format, inclusive. Example: '2026-01-31' |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| country | No | ||
| start_date | No | ||
| end_date | No | ||
| working_days | No | ||
| holidays_excluded | No | ||
| error | No |
Implementation Reference
- index.js:696-705 (registration)Registration of the 'calculate_working_days_eu' tool via server.registerTool() with inputSchema, outputSchema, and description for multi-country EU working day calculation.
server.registerTool("calculate_working_days_eu", { description: "Counts the number of working days between two dates (inclusive) for a given European country, excluding weekends and that country's national public holidays. Returns { country, start_date, end_date, working_days, holidays_excluded }. Supports PT, ES, FR, DE, IT, NL, BE, UK. Use when calculating cross-border SLA periods, invoice payment deadlines, or project timelines that must account for different national holiday calendars.", inputSchema: { country_code: z.string().describe("Two-letter ISO country code. Example: 'DE', 'IT', 'UK'"), start_date: z.string().describe("Start date in YYYY-MM-DD format, inclusive. Example: '2026-01-01'"), end_date: z.string().describe("End date in YYYY-MM-DD format, inclusive. Example: '2026-01-31'") }, outputSchema: { country: z.string().optional(), start_date: z.string().optional(), end_date: z.string().optional(), working_days: z.number().optional(), holidays_excluded: z.number().optional(), error: z.string().optional() }, annotations: { title: "Calculate Working Days (EU Multi-Country)", readOnlyHint: true, idempotentHint: true, openWorldHint: false } }, async ({ country_code, start_date, end_date }) => { - index.js:705-760 (handler)Handler function that calculates working days between two dates for a given European country, excluding weekends and national public holidays (including Easter-based movable holidays).
}, async ({ country_code, start_date, end_date }) => { const holidaysByCountry = { PT: ["01-01","04-25","05-01","06-10","08-15","10-05","11-01","12-01","12-08","12-25"], ES: ["01-01","01-06","05-01","08-15","10-12","11-01","12-06","12-08","12-25"], DE: ["01-01","05-01","10-03","12-25","12-26"], IT: ["01-01","01-06","04-25","05-01","06-02","08-15","11-01","12-08","12-25","12-26"], NL: ["01-01","04-27","05-05","12-25","12-26"], BE: ["01-01","05-01","07-21","08-15","11-01","11-11","12-25"], UK: ["01-01","12-25","12-26"], }; const getEasterHolidays = (year, country) => { const a = year % 19, b = Math.floor(year / 100), c = year % 100; const d = Math.floor(b / 4), e = b % 4, f = Math.floor((b + 8) / 25); const g = Math.floor((b - f + 1) / 3), h = (19 * a + b - d - g + 15) % 30; const i = Math.floor(c / 4), k = c % 4, 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; const easter = new Date(year, month - 1, day); const addDays = (date, days) => { const dd = new Date(date); dd.setDate(dd.getDate() + days); return dd; }; const fmt = (dd) => dd.toISOString().split("T")[0]; const dates = []; if (country === "FR") { dates.push(fmt(addDays(easter, 1)), fmt(addDays(easter, 39)), fmt(addDays(easter, 50))); } if (country === "DE") { dates.push(fmt(addDays(easter, -2)), fmt(addDays(easter, 1)), fmt(addDays(easter, 39)), fmt(addDays(easter, 50))); } if (country === "NL") { dates.push(fmt(addDays(easter, -2)), fmt(addDays(easter, 1)), fmt(addDays(easter, 39)), fmt(addDays(easter, 50))); } if (country === "BE") { dates.push(fmt(addDays(easter, 1)), fmt(addDays(easter, 39)), fmt(addDays(easter, 50))); } if (country === "UK") { dates.push(fmt(addDays(easter, -2)), fmt(addDays(easter, 1))); } return dates; }; const code = country_code.toUpperCase(); const supportedCountries = ["PT", "ES", "FR", "DE", "IT", "NL", "BE", "UK"]; if (!supportedCountries.includes(code)) return { content: [{ type: "text", text: JSON.stringify({ error: `Country ${code} not supported. Supported: ${supportedCountries.join(", ")}` }) }] }; const start = new Date(start_date), end = new Date(end_date); if (isNaN(start) || isNaN(end)) return { content: [{ type: "text", text: JSON.stringify({ error: "Invalid date format. Use YYYY-MM-DD" }) }] }; const fixedHolidays = holidaysByCountry[code] || []; let count = 0, holidaysExcluded = 0; const current = new Date(start); while (current <= end) { const dow = current.getDay(); const mmdd = `${String(current.getMonth() + 1).padStart(2, "0")}-${String(current.getDate()).padStart(2, "0")}`; const fullDate = current.toISOString().split("T")[0]; const year = current.getFullYear(); const easterHolidays = getEasterHolidays(year, code); const isHoliday = fixedHolidays.includes(mmdd) || easterHolidays.includes(fullDate); if (dow !== 0 && dow !== 6 && !isHoliday) count++; else if (dow !== 0 && dow !== 6 && isHoliday) holidaysExcluded++; current.setDate(current.getDate() + 1); } return { content: [{ type: "text", text: JSON.stringify({ country: code, start_date, end_date, working_days: count, holidays_excluded: holidaysExcluded }) }] }; }); - index.js:698-704 (schema)Input/output schema definitions for calculate_working_days_eu: country_code, start_date, end_date inputs; country, start_date, end_date, working_days, holidays_excluded outputs.
inputSchema: { country_code: z.string().describe("Two-letter ISO country code. Example: 'DE', 'IT', 'UK'"), start_date: z.string().describe("Start date in YYYY-MM-DD format, inclusive. Example: '2026-01-01'"), end_date: z.string().describe("End date in YYYY-MM-DD format, inclusive. Example: '2026-01-31'") }, outputSchema: { country: z.string().optional(), start_date: z.string().optional(), end_date: z.string().optional(), working_days: z.number().optional(), holidays_excluded: z.number().optional(), error: z.string().optional() }, annotations: { title: "Calculate Working Days (EU Multi-Country)", readOnlyHint: true, idempotentHint: true, openWorldHint: false } - index.js:706-714 (helper)Fixed holidays by country lookup table (holidaysByCountry) used by the handler for PT, ES, DE, IT, NL, BE, UK.
const holidaysByCountry = { PT: ["01-01","04-25","05-01","06-10","08-15","10-05","11-01","12-01","12-08","12-25"], ES: ["01-01","01-06","05-01","08-15","10-12","11-01","12-06","12-08","12-25"], DE: ["01-01","05-01","10-03","12-25","12-26"], IT: ["01-01","01-06","04-25","05-01","06-02","08-15","11-01","12-08","12-25","12-26"], NL: ["01-01","04-27","05-05","12-25","12-26"], BE: ["01-01","05-01","07-21","08-15","11-01","11-11","12-25"], UK: ["01-01","12-25","12-26"], }; - index.js:716-734 (helper)Helper function getEasterHolidays() that calculates Easter-based movable holidays (Good Friday, Easter Monday, Ascension, Whit Monday) per country.
const getEasterHolidays = (year, country) => { const a = year % 19, b = Math.floor(year / 100), c = year % 100; const d = Math.floor(b / 4), e = b % 4, f = Math.floor((b + 8) / 25); const g = Math.floor((b - f + 1) / 3), h = (19 * a + b - d - g + 15) % 30; const i = Math.floor(c / 4), k = c % 4, 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; const easter = new Date(year, month - 1, day); const addDays = (date, days) => { const dd = new Date(date); dd.setDate(dd.getDate() + days); return dd; }; const fmt = (dd) => dd.toISOString().split("T")[0]; const dates = []; if (country === "FR") { dates.push(fmt(addDays(easter, 1)), fmt(addDays(easter, 39)), fmt(addDays(easter, 50))); } if (country === "DE") { dates.push(fmt(addDays(easter, -2)), fmt(addDays(easter, 1)), fmt(addDays(easter, 39)), fmt(addDays(easter, 50))); } if (country === "NL") { dates.push(fmt(addDays(easter, -2)), fmt(addDays(easter, 1)), fmt(addDays(easter, 39)), fmt(addDays(easter, 50))); } if (country === "BE") { dates.push(fmt(addDays(easter, 1)), fmt(addDays(easter, 39)), fmt(addDays(easter, 50))); } if (country === "UK") { dates.push(fmt(addDays(easter, -2)), fmt(addDays(easter, 1))); } return dates; };