Skip to content

rrulenet/rrule

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rrule.net

@rrulenet/rrule

Classic rrule.js-style recurrence API, backed by a maintained engine built for production scheduling.

rrule.netTemporal API@rrulenet ecosystem

@rrulenet/rrule · @rrulenet/recurrence · @rrulenet/core · @rrulenet/cli

npm version Coverage MIT License

@rrulenet/rrule: classic API · @rrulenet/recurrence: Temporal-first API · @rrulenet/core: engine · @rrulenet/cli: workflows

@rrulenet/rrule provides the classic rrule.js-style API in the ecosystem. It is designed for compatibility-focused applications that want familiar classes, stable recurrence behavior, timezone-aware queries, set composition, and text rendering.

Use @rrulenet/rrule when you want the familiar class-based compat surface. Use @rrulenet/recurrence when your application boundary is already built around the Temporal API and a single Recurrence type.

Table of Contents

Install

npm install @rrulenet/rrule

Why RRule

@rrulenet/rrule exists for applications that want the classic recurrence model:

  • RRule for one rule
  • RRuleSet for composed include/exclude schedules
  • rrulestr() for parsing and round-tripping RFC-style strings
  • Date values at the API boundary

That makes it a good fit for:

  • migrations from rrule.js
  • existing codebases built around Date
  • applications that want a familiar class-based API without moving their boundary to Temporal

See also:

API

import {
  RRule,
  RRuleSet,
  SetAlgebra,
  rrulestr,
  Frequency,
  Weekday,
  ALL_WEEKDAYS,
  datetime,
  getToTextLocale,
  listToTextLocales,
  registerToTextLocale,
} from '@rrulenet/rrule';

Main exports:

  • RRule
  • RRuleSet
  • SetAlgebra
  • rrulestr
  • Frequency
  • Weekday
  • ALL_WEEKDAYS
  • datetime
  • getToTextLocale
  • listToTextLocales
  • registerToTextLocale

Recommended usage:

  • choose @rrulenet/rrule when you want the familiar class-based compat surface
  • choose @rrulenet/recurrence when your app boundary is built around the Temporal API
  • avoid importing from @rrulenet/core directly in application code

Getting Started

import { RRule, Frequency, datetime } from '@rrulenet/rrule';

const rule = new RRule({
  freq: Frequency.WEEKLY,
  count: 4,
  byweekday: [RRule.MO, RRule.WE],
  dtstart: datetime(2026, 4, 13, 9, 0, 0),
});

console.log(rule.all().map((value) => value.toISOString()));
// [
//   '2026-04-13T09:00:00.000Z',
//   '2026-04-15T09:00:00.000Z',
//   '2026-04-20T09:00:00.000Z',
//   '2026-04-22T09:00:00.000Z'
// ]

Examples

RRule

import { RRule, Frequency, datetime } from '@rrulenet/rrule';

const rule = new RRule({
  freq: Frequency.MONTHLY,
  bymonthday: [1, 15],
  count: 4,
  dtstart: datetime(2026, 1, 1, 9, 0, 0),
});

console.log(rule.toString());
// DTSTART:20260101T090000Z
// RRULE:FREQ=MONTHLY;COUNT=4;BYMONTHDAY=1,15

console.log(rule.toText());
// every month on the 1st and 15th day of the month at 9 AM UTC for 4 times

RRuleSet

import { RRule, RRuleSet, Frequency, datetime } from '@rrulenet/rrule';

const set = new RRuleSet();
set.tzid('UTC');
set.rrule(new RRule({
  freq: Frequency.DAILY,
  count: 4,
  dtstart: datetime(2026, 4, 11, 9, 0, 0),
}));
set.exdate(new Date('2026-04-12T09:00:00.000Z'));
set.rdate(new Date('2026-04-20T09:00:00.000Z'));

console.log(set.all().map((value) => value.toISOString()));
// [
//   '2026-04-11T09:00:00.000Z',
//   '2026-04-13T09:00:00.000Z',
//   '2026-04-14T09:00:00.000Z',
//   '2026-04-20T09:00:00.000Z'
// ]

console.log(set.toString());
// DTSTART:20260411T090000Z
// RRULE:FREQ=DAILY;COUNT=4
// RDATE:20260420T090000Z
// EXDATE:20260412T090000Z

SetAlgebra

import { RRule, SetAlgebra, Frequency, datetime } from '@rrulenet/rrule';

const expression = SetAlgebra.union(
  new RRule({
    freq: Frequency.WEEKLY,
    count: 3,
    byweekday: [RRule.MO],
    dtstart: datetime(2026, 4, 13, 9, 0, 0),
  }),
  new RRule({
    freq: Frequency.WEEKLY,
    count: 3,
    byweekday: [RRule.WE],
    dtstart: datetime(2026, 4, 15, 9, 0, 0),
  }),
);

console.log(expression.all().map((value) => value.toISOString()));
// [
//   '2026-04-13T09:00:00.000Z',
//   '2026-04-15T09:00:00.000Z',
//   '2026-04-20T09:00:00.000Z',
//   '2026-04-22T09:00:00.000Z',
//   '2026-04-27T09:00:00.000Z',
//   '2026-04-29T09:00:00.000Z'
// ]

rrulestr()

import { RRuleSet, rrulestr } from '@rrulenet/rrule';

const parsed = rrulestr([
  'DTSTART;TZID=UTC:20260411T090000',
  'RRULE:FREQ=DAILY;COUNT=2',
  'RDATE:20260415T090000Z',
  'EXDATE:20260412T090000Z',
].join('\n'));

console.log(parsed instanceof RRuleSet);
// true

console.log(parsed.toString());
// DTSTART:20260411T090000Z
// RRULE:FREQ=DAILY;COUNT=2
// RDATE:20260415T090000Z
// EXDATE:20260412T090000Z

Notes

  • RSCALE and SKIP are part of the compat rule model.
  • toText() and locale registry helpers are available here.
  • The same engine also powers the Temporal-first API exposed by @rrulenet/recurrence.

Development

npm install
npm test

About

Classic rrule.js-style recurrence API, backed by a maintained engine built for production scheduling.

Topics

Resources

Security policy

Stars

Watchers

Forks

Releases

Used by

Contributors

Languages