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

@rrulenet/rrule

v0.1.3

Published

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

Readme

@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