npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

quickurrence

v0.3.0

Published

A powerful, type-safe recurrence rule engine for generating recurring dates with timezone support

Readme

Quickurrence

npm version License: MIT TypeScript

A powerful, type-safe recurrence rule engine for TypeScript. Generate recurring dates with full timezone support, built on date-fns and Zod.

Why Quickurrence?

  • Type-safe: Full TypeScript support with exported types and Zod schemas for runtime validation
  • Timezone-aware: Built-in timezone handling via @date-fns/tz
  • Flexible: Daily, weekly, monthly, yearly rules with presets, nth weekday, custom conditions, and more
  • Composable: Merge multiple recurrence rules into unified date sequences
  • Validated: Built-in validator with detailed, actionable error messages

Installation

pnpm add quickurrence
# or
npm install quickurrence
# or
yarn add quickurrence

Quick Start

import { Quickurrence } from 'quickurrence';

// Every day starting from a date
const daily = new Quickurrence({
  rule: 'daily',
  startDate: new Date('2026-01-01'),
  timezone: 'America/New_York',
});

const next5Days = daily.getNextOccurrences(5);

// Every Monday and Wednesday
const weekdays = new Quickurrence({
  rule: 'weekly',
  startDate: new Date('2026-01-01'),
  timezone: 'Europe/London',
  weekDays: [1, 3], // Monday, Wednesday
});

// First business day of each month
const monthly = new Quickurrence({
  rule: 'monthly',
  startDate: new Date('2026-01-01'),
  timezone: 'Asia/Tokyo',
  monthDay: 1,
});

// Business days only (preset)
const businessDays = new Quickurrence({
  rule: 'daily',
  startDate: new Date('2026-01-01'),
  timezone: 'America/Chicago',
  preset: 'businessDays',
});

API Reference

Quickurrence

The main class for defining and generating recurrence rules.

Constructor Options

| Option | Type | Required | Description | |--------|------|----------|-------------| | rule | 'daily' \| 'weekly' \| 'monthly' \| 'yearly' | Yes | Recurrence frequency | | startDate | Date | Yes | Start date for the recurrence | | timezone | string | No | IANA timezone identifier | | interval | number | No | Interval between occurrences (e.g., every 2 weeks) | | endDate | Date | No | End date for the recurrence | | count | number | No | Maximum number of occurrences | | weekStartsOn | Day (0-6) | No | First day of the week (0 = Sunday) | | weekDays | Day[] | No | Days of the week for weekly rules | | monthDay | MonthDay (1-31) | No | Day of the month for monthly rules | | monthDayMode | 'skip' \| 'last' | No | How to handle months without the specified day | | nthWeekdayOfMonth | NthWeekdayConfig | No | Nth weekday of month (e.g., 2nd Tuesday) | | excludeDates | Date[] | No | Dates to exclude from the recurrence | | condition | boolean \| ((date: Date) => boolean) | No | Custom filter condition | | preset | 'businessDays' \| 'weekends' | No | Predefined day-of-week filters | | timesOfDay | string[] ("HH:MM") | No | Times of day to fire on each matching day (24-hour format, e.g. ['09:00', '14:30']) |

Methods

  • getNextOccurrences(count: number): Date[] - Get the next N occurrences
  • getOccurrencesInRange(range: DateRange): Date[] - Get occurrences within a date range
  • getNextOccurrence(): Date | null - Get the next single occurrence
  • isOccurrence(date: Date): boolean - Check if a date matches the recurrence rule

QuickurrenceMerge

Merge multiple recurrence rules into a single sorted sequence.

import { Quickurrence, QuickurrenceMerge } from 'quickurrence';

const rule1 = new Quickurrence({ rule: 'weekly', startDate: new Date(), weekDays: [1] });
const rule2 = new Quickurrence({ rule: 'weekly', startDate: new Date(), weekDays: [4] });

const merged = new QuickurrenceMerge([rule1, rule2]);
const dates = merged.getNextOccurrences(10); // Combined Monday + Thursday dates

QuickurrenceValidator

Validates QuickurrenceOptions and provides detailed error messages.

import { QuickurrenceValidator } from 'quickurrence';

QuickurrenceValidator.validateOptions({
  rule: 'weekly',
  startDate: new Date(),
  weekDays: [1, 3, 5],
});

Exported Types

import type {
  RecurrenceRule,
  Preset,
  DateRange,
  WeekStartsOn,
  WeekDay,
  MonthDay,
  MonthDayMode,
  NthWeekdayOfMonth,
  NthWeekdayConfig,
  Condition,
  QuickurrenceOptions,
} from 'quickurrence';

Exported Zod Schemas

import {
  RecurrenceRuleSchema,
  DateRangeSchema,
  WeekStartsOnSchema,
  WeekDaySchema,
  MonthDaySchema,
  NthWeekdayOfMonthSchema,
  CountSchema,
  IntervalSchema,
  TimeOfDaySchema,
  TimesOfDaySchema,
  QuickurrenceOptionsSchema,
} from 'quickurrence';

Advanced Examples

Nth Weekday of Month

// Second Tuesday of every month
const rule = new Quickurrence({
  rule: 'monthly',
  startDate: new Date('2026-01-01'),
  timezone: 'America/New_York',
  nthWeekdayOfMonth: { weekday: 2, nth: 2 },
});

// Last Friday of every month
const lastFriday = new Quickurrence({
  rule: 'monthly',
  startDate: new Date('2026-01-01'),
  timezone: 'America/New_York',
  nthWeekdayOfMonth: { weekday: 5, nth: 'last' },
});

Multiple Times Per Day

// Every Monday and Wednesday at 09:00 and 14:30 (Warsaw wall-clock)
const rule = new Quickurrence({
  rule: 'weekly',
  weekDays: [1, 3],
  startDate: new Date('2026-01-05'),
  timezone: 'Europe/Warsaw',
  timesOfDay: ['09:00', '14:30'],
});

// Each datetime counts as one occurrence — `count: 5` returns 5 datetimes,
// not 5 days. `endDate` and `excludeDates` are matched as exact datetimes
// when `timesOfDay` is set. Wall-clock time is preserved across DST.

Custom Conditions

// Every day, but only if it's not a holiday
const holidays = [new Date('2026-12-25'), new Date('2026-01-01')];

const rule = new Quickurrence({
  rule: 'daily',
  startDate: new Date('2026-01-01'),
  timezone: 'America/New_York',
  condition: (date) => !holidays.some(h => h.getTime() === date.getTime()),
});

With Date Range

const rule = new Quickurrence({
  rule: 'weekly',
  startDate: new Date('2026-01-01'),
  timezone: 'Europe/Berlin',
  weekDays: [1, 3, 5],
});

const dates = rule.getOccurrencesInRange({
  start: new Date('2026-02-01'),
  end: new Date('2026-02-28'),
});

Error Handling

Quickurrence provides structured errors with error codes for programmatic handling:

import { QuickurrenceError, QuickurrenceErrorCode } from 'quickurrence';

try {
  new Quickurrence({ rule: 'weekly', startDate: new Date(), weekDays: [] });
} catch (error) {
  if (error instanceof QuickurrenceError) {
    console.log(error.code);    // QuickurrenceErrorCode.EMPTY_REQUIRED_ARRAY
    console.log(error.type);    // QuickurrenceErrorType.VALIDATION
    console.log(error.context); // { option: 'weekDays', ... }
  }
}

Contributing

Contributions are welcome! Please read the Contributing Guide before submitting a pull request.

License

MIT