~/recurring-dates
docs

Config Reference

Every option you can pass to generateRecurringDates, getRecurringDates, or useRecurringDates.

STARTS_ONrequired
Typestring
Default

The start date of the recurrence range. Parsed using the value of FORMAT. Must be a valid date string matching the chosen format.

Example

STARTS_ON
generateRecurringDates({
  STARTS_ON: "01-01-2025",
  ENDS_ON:   "31-01-2025",
  FREQUENCY: "D",
});
ENDS_ONrequired
Typestring
Default

The end date of the recurrence range. Must be on or after STARTS_ON. Parsed using the value of FORMAT.

Example

ENDS_ON
generateRecurringDates({
  STARTS_ON: "01-01-2025",
  ENDS_ON:   "31-03-2025",  // generate through March
  FREQUENCY: "W",
  WEEK_DAYS: ["MON"],
});
FREQUENCY
Type"D" | "W" | "M" | "Y"
Default"D"

Controls how often dates recur. "D" = Daily, "W" = Weekly, "M" = Monthly, "Y" = Yearly.

Example

FREQUENCY
// Daily
generateRecurringDates({ STARTS_ON: "01-01-2025", ENDS_ON: "07-01-2025", FREQUENCY: "D" });

// Weekly
generateRecurringDates({ STARTS_ON: "01-01-2025", ENDS_ON: "31-01-2025", FREQUENCY: "W", WEEK_DAYS: ["MON"] });

// Monthly
generateRecurringDates({ STARTS_ON: "01-01-2025", ENDS_ON: "31-12-2025", FREQUENCY: "M", MONTH_DATES: [1] });

// Yearly
generateRecurringDates({
  STARTS_ON:     "01-01-2025",
  ENDS_ON:       "31-12-2027",
  FREQUENCY:     "Y",
  MONTH_NAMES:   ["JAN"],
  WEEK_ORDINALS: ["FIRST"],
  WEEK_DAYS:     ["MON"],
});
INTERVAL
Typenumber
Default1

Skip N cycles between occurrences. For example, INTERVAL: 2 with weekly frequency means every other week. INTERVAL: 3 with monthly means every third month.

Example

INTERVAL
// Every other week on Monday
generateRecurringDates({
  STARTS_ON: "01-01-2025",
  ENDS_ON:   "31-03-2025",
  FREQUENCY: "W",
  INTERVAL:  2,
  WEEK_DAYS: ["MON"],
});

// Every 3 months on the 1st
generateRecurringDates({
  STARTS_ON:   "01-01-2025",
  ENDS_ON:     "31-12-2025",
  FREQUENCY:   "M",
  INTERVAL:    3,
  MONTH_DATES: [1],
});
WEEK_DAYS
Type("SUN" | "MON" | "TUE" | "WED" | "THU" | "FRI" | "SAT")[]
Default["MON"]

Array of ISO weekday codes to include. Used with FREQUENCY: "W" (weekly) and FREQUENCY: "Y" (yearly ordinal patterns).

Example

WEEK_DAYS
// Every Mon, Wed, Fri
generateRecurringDates({
  STARTS_ON: "01-01-2025",
  ENDS_ON:   "31-01-2025",
  FREQUENCY: "W",
  WEEK_DAYS: ["MON", "WED", "FRI"],
});
// result.text → "Every week on Monday, Wednesday and Friday"
SUN
MON
TUE
WED
THU
FRI
SAT
MONTH_DATES
Typenumber[]
Default[1]

Specific calendar dates within each month (1–31). Used with FREQUENCY: "M". Dates that don't exist in a given month (e.g. 31 in February) are automatically skipped.

Example

MONTH_DATES
// 1st and 15th of every month
generateRecurringDates({
  STARTS_ON:   "01-01-2025",
  ENDS_ON:     "31-12-2025",
  FREQUENCY:   "M",
  MONTH_DATES: [1, 15],
});
// result.text → "Every month on 1st and 15th"
WEEK_ORDINALS
Type("FIRST" | "SECOND" | "THIRD" | "FOURTH" | "FIFTH" | "LAST")[]
Default["FIRST"]

Which occurrence of the weekday within the month to target. Used with FREQUENCY: "Y" to build ordinal patterns like "the last Friday of December".

Example

WEEK_ORDINALS
// Last Monday of January every year
generateRecurringDates({
  STARTS_ON:     "01-01-2025",
  ENDS_ON:       "31-12-2027",
  FREQUENCY:     "Y",
  MONTH_NAMES:   ["JAN"],
  WEEK_ORDINALS: ["LAST"],
  WEEK_DAYS:     ["MON"],
});
// result.text → "Every year on last Monday of January"
FIRST
SECOND
THIRD
FOURTH
FIFTH
LAST
MONTH_NAMES
Type("JAN"|"FEB"|"MAR"|"APR"|"MAY"|"JUN"|"JUL"|"AUG"|"SEP"|"OCT"|"NOV"|"DEC")[]
Default["JAN"]

Which months to include in a yearly recurrence. Used with FREQUENCY: "Y". Combine with WEEK_ORDINALS and WEEK_DAYS to describe the exact day.

Example

MONTH_NAMES
// First Monday of March and September every year
generateRecurringDates({
  STARTS_ON:     "01-01-2025",
  ENDS_ON:       "31-12-2027",
  FREQUENCY:     "Y",
  MONTH_NAMES:   ["MAR", "SEP"],
  WEEK_ORDINALS: ["FIRST"],
  WEEK_DAYS:     ["MON"],
});
JAN
FEB
MAR
APR
MAY
JUN
JUL
AUG
SEP
OCT
NOV
DEC
EXCLUDE_DATES
Typestring[]
Default[]

Dates to remove from the generated output. Each entry must be a valid date string matching FORMAT. Useful for skipping holidays or one-off exceptions.

Example

EXCLUDE_DATES
generateRecurringDates({
  STARTS_ON:     "01-01-2025",
  ENDS_ON:       "31-01-2025",
  FREQUENCY:     "W",
  WEEK_DAYS:     ["MON"],
  EXCLUDE_DATES: ["06-01-2025", "20-01-2025"],
});
// 06 Jan and 20 Jan will NOT appear in result.dates
FORMAT
Type"DD-MM-YYYY" | "MM-DD-YYYY" | "YYYY-MM-DD" | "MM/DD/YYYY" | "DD/MM/YYYY" | "MMM DD YYYY"
Default"DD-MM-YYYY"

Date format applied to both input parsing (STARTS_ON, ENDS_ON, EXCLUDE_DATES) and the output dates array. Pick one format and use it consistently throughout the config.

Example

FORMAT
// ISO format
generateRecurringDates({
  STARTS_ON: "2025-01-01",
  ENDS_ON:   "2025-03-31",
  FREQUENCY: "W",
  WEEK_DAYS: ["TUE", "THU"],
  FORMAT:    "YYYY-MM-DD",
});
// result.dates → ["2025-01-07", "2025-01-09", ...]

// Human-readable format
generateRecurringDates({
  STARTS_ON: "Jan 01 2025",
  ENDS_ON:   "Mar 31 2025",
  FREQUENCY: "M",
  MONTH_DATES: [1],
  FORMAT:    "MMM DD YYYY",
});
// result.dates → ["Jan 01 2025", "Feb 01 2025", "Mar 01 2025"]
FORMAT value
Example output
DD-MM-YYYY
31-01-2025
MM-DD-YYYY
01-31-2025
YYYY-MM-DD
2025-01-31
MM/DD/YYYY
01/31/2025
DD/MM/YYYY
31/01/2025
MMM DD YYYY
Jan 31 2025
TIMEZONE
Typestring
Defaultundefined

Optional IANA timezone identifier. When provided, date generation respects that timezone's calendar day boundaries. Omitting it (or passing null / undefined) falls back to local time. Any identifier accepted by Intl.DateTimeFormat is valid — e.g. 'America/New_York', 'Europe/London', 'Asia/Kolkata', 'UTC'.

Example

TIMEZONE
// Schedule weekly meetings in New York time
generateRecurringDates({
  STARTS_ON: "01-03-2025",
  ENDS_ON:   "31-03-2025",
  FREQUENCY: "W",
  WEEK_DAYS: ["MON", "WED", "FRI"],
  TIMEZONE:  "America/New_York",
});

// Auto-detect the current user's timezone
import { getUserTimezone } from "recurring-dates";
generateRecurringDates({ ..., TIMEZONE: getUserTimezone() });

// Invalid timezone → error object, no exception thrown
// { dates: [], error: "Invalid timezone: 'Bad/Zone' ..." }

Return Value

On Success

{ text: string, dates: string[] } text is a human-readable description (e.g. "Every week on Monday and Thursday"). dates is a sorted array of date strings in the specified format.

On Validation Error

{ dates: [], error: string } — The error field contains a descriptive validation message. The text field is omitted.

Validation Rules

  • Both STARTS_ON and ENDS_ON are required.
  • Dates must be valid according to FORMAT.
  • STARTS_ON must be before or equal to ENDS_ON.
  • Weekly frequency requires at least one WEEK_DAYS entry.
  • Monthly frequency requires at least one MONTH_DATES entry.
  • Yearly frequency requires MONTH_NAMES, WEEK_ORDINALS, and WEEK_DAYS.
  • All EXCLUDE_DATES must be valid according to FORMAT.
  • TIMEZONE must be a valid IANA timezone identifier when provided.