~/recurring-dates
docs

Examples

Real-world usage patterns for common scheduling scenarios.

Bi-Weekly Payroll

Generate pay days every two weeks on Friday:

Bi-Weekly Payroll
import { generateRecurringDates } from "recurring-dates";

const payroll = generateRecurringDates({
  STARTS_ON: "01-01-2025",
  ENDS_ON: "31-12-2025",
  FREQUENCY: "W",
  WEEK_DAYS: ["FRI"],
  INTERVAL: 2,
});

console.log(payroll.text);  // "Every 2 weeks on Friday"
console.log(payroll.dates); // 26 pay dates

Quarterly Board Meetings

First Monday of every quarter:

Quarterly Meetings
const meetings = generateRecurringDates({
  STARTS_ON: "01-01-2025",
  ENDS_ON: "31-12-2025",
  FREQUENCY: "Y",
  WEEK_ORDINALS: ["FIRST"],
  WEEK_DAYS: ["MON"],
  MONTH_NAMES: ["JAN", "APR", "JUL", "OCT"],
});

console.log(meetings.text);
// "Every year on First Monday of January, April, July and October"

Holiday-Aware Schedule

Weekly meetings excluding specific holidays:

With Holiday Exclusions
const schedule = generateRecurringDates({
  STARTS_ON: "01-01-2025",
  ENDS_ON: "31-03-2025",
  FREQUENCY: "W",
  WEEK_DAYS: ["MON", "WED", "FRI"],
  EXCLUDE_DATES: [
    "20-01-2025", // MLK Day
    "17-02-2025", // Presidents' Day
  ],
});

Custom Date Format

Use ISO format or any Moment.js-compatible format:

ISO Format
const result = generateRecurringDates({
  STARTS_ON: "2025-01-01",
  ENDS_ON: "2025-01-31",
  FREQUENCY: "W",
  WEEK_DAYS: ["TUE"],
  FORMAT: "YYYY-MM-DD",
});

// dates: ["2025-01-07", "2025-01-14", "2025-01-21", "2025-01-28"]

React Calendar Component

Using the hook to drive a calendar UI:

React Calendar
import { useRecurringDates } from "recurring-dates";

function EventCalendar({ startDate, endDate }) {
  const { dates, text } = useRecurringDates({
    STARTS_ON: startDate,
    ENDS_ON: endDate,
    FREQUENCY: "W",
    WEEK_DAYS: ["MON", "WED", "FRI"],
    FORMAT: "YYYY-MM-DD",
  });

  return (
    <div className="calendar">
      <h3>{text}</h3>
      <div className="grid grid-cols-7 gap-1">
        {dates.map((date) => (
          <div key={date} className="event-day">
            {date}
          </div>
        ))}
      </div>
    </div>
  );
}

Global Team Standups

Timezone

Generate the same daily standup schedule in multiple timezones — useful when building multi-region calendar tools. See Timezone Support for full API details.

Global Team Standups
import { generateRecurringDates } from "recurring-dates";

const regions = [
  { name: "New York",  tz: "America/New_York" },
  { name: "London",   tz: "Europe/London" },
  { name: "Dubai",    tz: "Asia/Dubai" },
  { name: "Tokyo",    tz: "Asia/Tokyo" },
];

const standups = regions.map(({ name, tz }) => ({
  region: name,
  result: generateRecurringDates({
    STARTS_ON: "2025-01-01",
    ENDS_ON:   "2025-01-07",
    FREQUENCY: "D",
    FORMAT:    "YYYY-MM-DD",
    TIMEZONE:  tz,
  }),
}));

standups.forEach(({ region, result }) => {
  console.log(`${region}: ${result.dates.join(", ")}`);
});

Monthly Billing Per Customer

Timezone

Generate billing dates anchored to each customer’s local timezone so invoices always arrive on the 1st of their month, not UTC’s.

Monthly Billing Per Customer
import { generateRecurringDates } from "recurring-dates";

function getBillingDates(customerTimezone) {
  return generateRecurringDates({
    STARTS_ON:   "2025-01-01",
    ENDS_ON:     "2025-12-31",
    FREQUENCY:   "M",
    MONTH_DATES: [1],
    FORMAT:      "YYYY-MM-DD",
    TIMEZONE:    customerTimezone,
  });
}

const nyBilling = getBillingDates("America/New_York");
const jpBilling = getBillingDates("Asia/Tokyo");

console.log(nyBilling.text);
// "Every month on 1st"
console.log(nyBilling.dates.length); // 12

Auto-Detect User Timezone (React)

Timezone

Combine useRecurringDates with getUserTimezone() to automatically localise dates to the visitor’s browser timezone.

Auto-Detect User Timezone (React)
import { useRecurringDates, getUserTimezone } from "recurring-dates";

function LocalisedSchedule() {
  const userTz = getUserTimezone(); // e.g. "Europe/Paris"

  const { dates, text } = useRecurringDates({
    STARTS_ON: "2025-06-01",
    ENDS_ON:   "2025-06-30",
    FREQUENCY: "W",
    WEEK_DAYS: ["MON", "WED", "FRI"],
    FORMAT:    "YYYY-MM-DD",
    TIMEZONE:  userTz,
  });

  return (
    <div>
      <p>{text}</p>
      <p>Localised to: {userTz}</p>
      <ul>
        {dates.map((d) => <li key={d}>{d}</li>)}
      </ul>
    </div>
  );
}

Spaced Repetition

Every 3 days for a study schedule:

Spaced Repetition
const studyDays = generateRecurringDates({
  STARTS_ON: "01-01-2025",
  ENDS_ON: "31-03-2025",
  FREQUENCY: "D",
  INTERVAL: 3,
});

console.log(studyDays.text);  // "Every 3 days"
console.log(studyDays.dates.length); // ~30 study sessions

Last Friday of Every Month (Yearly)

Monthly close-of-business reports on the last Friday:

Last Friday of Every Month
const reports = generateRecurringDates({
  STARTS_ON: "01-01-2025",
  ENDS_ON: "31-12-2025",
  FREQUENCY: "Y",
  WEEK_ORDINALS: ["LAST"],
  WEEK_DAYS: ["FRI"],
  MONTH_NAMES: [
    "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
    "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
  ],
});

console.log(reports.text);
// "Every year on Last Friday of January, February, ... and December"