UNPKG

@laxmandarji/schedule-date-calculator

Version:

A powerful JavaScript/TypeScript library for calculating eligible run dates based on complex scheduling rules. Perfect for job schedulers, task automation, and business calendar management.

434 lines (342 loc) โ€ข 10.9 kB
# Schedule Date Calculator [![npm version](https://img.shields.io/npm/v/@laxmandarji/schedule-date-calculator.svg)](https://www.npmjs.com/package/@laxmandarji/schedule-date-calculator) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) A powerful JavaScript/TypeScript library for calculating eligible run dates based on complex scheduling rules. Perfect for job schedulers, task automation, and business calendar management. ## What's New in v4 ### Version 4.0.0 - Added "WORKDAYS" keyword support in MONTHDAYS rules to easily include or exclude all working days - Improved exclusion rule handling - exclusions now take precedence and are evaluated first - Enhanced performance by processing exclusions before inclusions - Fixed edge cases in weekday and monthday rule evaluation - Breaking change: Changed behavior of exclusion rules (-) to take precedence over inclusion rules ## Features - ๐Ÿ“… Define custom business calendars with working days and holidays - ๐Ÿ”„ Flexible scheduling patterns (daily, weekly, monthly) - ๐ŸŽฏ Advanced modifiers for precise scheduling control - ๐Ÿ“Š Support for complex business logic - โšก Efficient date calculations with caching - ๐Ÿ›ก๏ธ Comprehensive validation and error handling - ๐Ÿ“˜ Full TypeScript support - ๐Ÿš€ Optimized performance - ๐Ÿงช Modular architecture ## Installation ```bash npm install @laxmandarji/schedule-date-calculator ``` ## Usage The library supports both CommonJS and ES Modules: ```javascript // CommonJS const { ScheduleConfig } = require('@laxmandarji/schedule-date-calculator'); // ES Modules import { ScheduleConfig } from '@laxmandarji/schedule-date-calculator'; ``` ## Configuration Create a new schedule configuration: ```javascript const config = new ScheduleConfig({ CALENDARS: { WORKWEEK: { WORKDAYS: [1, 2, 3, 4, 5], // Mon-Fri HOLIDAYS: ["2024-12-25", "2024-01-01"] } }, WEEKDAYS_CALENDAR: "WORKWEEK", WEEKDAYS: ["D1", "D2"], // First and second working days MONTHS: ["JAN", "FEB", "MAR"] // First quarter }); ``` ### Configuration Options - `CALENDARS`: Object containing named calendars with workdays and holidays - `WORKDAYS`: Array of working days (0-6, where 0 is Sunday) - `HOLIDAYS`: Array of holiday dates in "YYYY-MM-DD" format - `WEEKDAYS_CALENDAR`: Name of the calendar to use for weekday calculations - `WEEKDAYS`: Array of weekday specifications - `WEEK_MONTH_RELATION`: Relationship between week and month rules ("AND" or "OR", defaults to "OR") - `MONTH_CALENDAR`: Name of the calendar to use for monthday calculations - `MONTHDAYS`: Array of monthday specifications - `MONTHS`: Array of month names (e.g., ["JAN", "FEB", "MAR"]) ## Methods ### change(config) Completely replaces the current configuration with a new one. All properties are reset to their default values if not specified in the new configuration. ```javascript config.change({ CALENDARS: { NEWCAL: { WORKDAYS: [1, 2, 3], // Mon-Wed HOLIDAYS: ["2024-12-25"] } }, WEEKDAYS: ["D1"], // First working day only MONTHS: ["JAN"] // January only }); ``` ### update(newConfig) Updates specific properties of the configuration while keeping others unchanged. ```javascript config.update({ WEEKDAYS: ["D1", "D2"], // Only updates WEEKDAYS MONTHS: ["JAN", "FEB"] // Only updates MONTHS }); ``` ### addCalendar(calendarName, workdays, holidays) Adds or updates a calendar in the configuration. ```javascript config.addCalendar( "CUSTOM_CAL", [1, 2, 3, 4, 5], // Mon-Fri ["2024-12-25", "2024-01-01"] ); ``` ### isDateEligible(date) Checks if a specific date is eligible according to the configuration. ```javascript const date = new Date('2024-01-02'); const isEligible = config.isDateEligible(date); ``` ### getEligibleDates(year) Gets all eligible dates for a specific year. ```javascript const dates = config.getEligibleDates(2024); ``` ### validate() Validates the current configuration. ```javascript const validation = config.validate(); if (!validation.isValid) { console.error('Configuration errors:', validation.errors); } ``` ## Examples ### Basic Usage ```javascript const config = new ScheduleConfig({ CALENDARS: { WORKWEEK: { WORKDAYS: [1, 2, 3, 4, 5], // Mon-Fri HOLIDAYS: ["2024-12-25"] } }, WEEKDAYS_CALENDAR: "WORKWEEK", WEEKDAYS: ["D1"], // First working day MONTHS: ["JAN", "FEB"] // Jan-Feb only }); // Get eligible dates for 2024 const dates = config.getEligibleDates(2024); console.log('Eligible dates:', dates); ``` ### Changing Configuration ```javascript // Initial configuration const config = new ScheduleConfig({ CALENDARS: { WORKWEEK: { WORKDAYS: [1, 2, 3, 4, 5], HOLIDAYS: ["2024-12-25"] } } }); // Complete configuration change config.change({ CALENDARS: { CUSTOM: { WORKDAYS: [1, 2, 3], HOLIDAYS: ["2024-01-01"] } }, WEEKDAYS: ["D1"], MONTHS: ["JAN"] }); // Partial update config.update({ WEEKDAYS: ["D1", "D2"] }); ``` ## Configuration Guide ### Calendar Configuration Define business calendars with working days and holidays: ```typescript const config = new ScheduleConfig({ CALENDARS: { US_BUSINESS: { WORKDAYS: [1, 2, 3, 4, 5], // Monday-Friday HOLIDAYS: ["2025-01-01", "2025-12-25"] }, ASIA_BUSINESS: { WORKDAYS: [1, 2, 3, 4, 5, 6], // Monday-Saturday HOLIDAYS: ["2025-01-01"] } } }); ``` ### Weekday Rules Multiple formats for weekday scheduling: ```typescript { WEEKDAYS_CALENDAR: "US_BUSINESS", WEEKDAYS: [ "1", // Every Monday ">3", // Run on next working day if Wednesday is not a working day "<3", // Run on previous working day if Wednesday is not a working day "+3", // Force run on Wednesday (even if holiday) "-3", // Never run on Wednesday "D2", // 2nd working day of each week "D3W2" // Wednesday of 2nd week ] } ``` ### Monthday Rules Flexible monthly scheduling: ```typescript { MONTH_CALENDAR: "US_BUSINESS", MONTHDAYS: [ "WORKDAYS", // All working days "-WORKDAYS", // No working days "1", // 1st day of month ">15", // Run on next working day if 15th is not a working day "<15", // Run on previous working day if 15th is not a working day "+15", // Force run on 15th (even if holiday) "-15", // Skip 15th "D5", // 5th working day "L1", // Last working day "L5" // 5th to last working day ] } ``` ### Month Selection Specify months to run: ```typescript { MONTHS: ["JAN", "APR", "JUL", "OCT"], // Quarterly // or MONTHS: ["ALL"] // Run every month } ``` ### Week-Month Relation Control how weekday and monthday rules combine: ```typescript { WEEK_MONTH_RELATION: "AND", // Must satisfy both conditions // or WEEK_MONTH_RELATION: "OR" // Must satisfy either condition (default) } ``` ## Advanced Examples ### Working Days Only Schedule ```typescript const config = new ScheduleConfig({ CALENDARS: { BUSINESS: { WORKDAYS: [1, 2, 3, 4, 5], HOLIDAYS: ["2025-01-01"] } }, MONTH_CALENDAR: "BUSINESS", MONTHDAYS: ["WORKDAYS"], // Run on all working days MONTHS: ["ALL"] }); ``` ### Non-Working Days Only Schedule ```typescript const config = new ScheduleConfig({ CALENDARS: { BUSINESS: { WORKDAYS: [1, 2, 3, 4, 5], HOLIDAYS: ["2025-01-01"] } }, MONTH_CALENDAR: "BUSINESS", MONTHDAYS: ["-WORKDAYS", "15"], // Run on non-working days and 15th MONTHS: ["ALL"] }); ``` ### Complex Weekly Pattern ```typescript const config = new ScheduleConfig({ CALENDARS: { BUSINESS: { WORKDAYS: [1, 2, 3, 4, 5], HOLIDAYS: ["2025-04-01"] } }, WEEKDAYS_CALENDAR: "BUSINESS", WEEKDAYS: [ "D2W1", // Tuesday of first week "D4W3", // Thursday of third week ">3" // Next working day after Wednesday ], MONTHS: ["ALL"] }); ``` ### Holiday-Aware Monthly Schedule ```typescript const config = new ScheduleConfig({ CALENDARS: { BUSINESS: { WORKDAYS: [1, 2, 3, 4, 5], HOLIDAYS: ["2025-04-01"] } }, MONTH_CALENDAR: "BUSINESS", MONTHDAYS: [ "WORKDAYS", // All working days "-15", // Except the 15th "L1" // And include the last working day ], MONTHS: ["APR"] }); ``` ## API Reference ### Namespaces The library is organized into logical namespaces: #### utils ```typescript import { utils } from '@laxmandarji/schedule-date-calculator'; utils.validateConfig(config); utils.formatDate(date); utils.getWeekOfMonth(date); ``` #### dateCalculators ```typescript import { dateCalculators } from '@laxmandarji/schedule-date-calculator'; dateCalculators.isWorkingDay(date, calendar); dateCalculators.getNthWorkdayOfMonth(date, n, calendar); dateCalculators.getLastNthWorkdayOfMonth(date, n, calendar); ``` #### evaluators ```typescript import { evaluators } from '@laxmandarji/schedule-date-calculator'; evaluators.evaluateWeekdays(date, config, calendars); evaluators.evaluateMonthdays(date, config, calendars); ``` ### ScheduleConfig Class #### Constructor ```typescript const config = new ScheduleConfig(configObject); ``` #### Methods ##### isDateEligible(date) ```typescript const date = new Date(2025, 3, 16); const isEligible = config.isDateEligible(date); ``` ##### getEligibleDates(year) ```typescript const dates = config.getEligibleDates(2025); ``` ##### validate() ```typescript const validation = config.validate(); if (!validation.isValid) { console.error(validation.errors); } ``` ## License MIT License - see LICENSE file for details. ## Contributing Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change. ## Support For support, please create an issue in the [GitHub repository](https://github.com/laxmandarji/schedule-date-calculator/issues). ## Author Laxman Darji