rruleByPattern.js
Build recurrence rules by patterns / templates like '111100' (i.e. 4 on, 2 off)
It is a rrule.js extension that gives more flexibility in creation of recurring events. The pattern / template can be absolutely custom and as long as you need. This extension is well suited for shift plan (rota, roster) set ups.
Quick Start
Install
$ yarn add rrule-by-pattern# or $ npm install rrule-by-pattern
Alternatively, download manually:
- rruleByPattern.min.js (bundled without rrule.js, minified)
- rruleByPattern.js (bundled without rrule.js, not minified)
As rrule.js is not bundled with rruleByPattern.js, it's needed to install or download it as well.
Then you will be able to use global variable rruleByPattern
(e.g. new rruleByPattern.ShortRRuleSetBuilder()
).
Usage
There are 2 builders. One builds readable rrule sets, another - short.
Both builders need 3 arguments: rruleSet
, pattern
, count
.
The rruleSet
is a rrule.js RRuleSet obviously and it should be built and then passed to the builder. The builder will build a new RRuleSet based on the passed one.
The pattern
is just an array of 0 and 1:
- 0 exclude date (e.g. shift off);
- 1 include date (e.g. shift on).
The count
is a number of dates you want to have in a built RRuleSet. For sets that have 'until' or 'count', it can be just rruleSet.count()
. For unlimited sets you should pick a count by yourself.
ReadableRRuleSetBuilder:
import { RRule, RRuleSet } from 'rrule'import { ReadableRRuleSetBuilder } from 'rrule-by-pattern' const rruleSet = new RRuleSet() rruleSet.rrule(new RRule({ freq: RRule.HOURLY, dtstart: new Date(Date.UTC(2025, 11, 25, 6)), until: new Date(Date.UTC(2025, 11, 30, 18)), interval: 12})) rruleSet.rrule(new RRule({ freq: RRule.DAILY, dtstart: new Date(Date.UTC(2026, 0, 1, 6)), until: new Date(Date.UTC(2026, 0, 30, 6)),})) // Original RRuleSet stringrruleSet.toString()DTSTART:20251225T060000ZRRULE:FREQ=HOURLY;UNTIL=20251230T180000Z;INTERVAL=12DTSTART:20260101T060000ZRRULE:FREQ=DAILY;UNTIL=20260130T060000Z const pattern: Array<0|1> = [1,1,1,1,0,0] const builder = new ReadableRRuleSetBuilder( rruleSet, pattern, rruleSet.count()) const newRRuleSet = builder.build() // Built RRuleSet stringnewRRuleSet.toString()DTSTART:20251225T060000ZRRULE:FREQ=HOURLY;UNTIL=20251230T180000Z;INTERVAL=12DTSTART:20260101T060000ZRRULE:FREQ=DAILY;UNTIL=20260130T060000ZEXDATE:20251227T060000Z,20251227T180000Z,20251230T060000Z,20251230T180000Z,20260105T060000Z,20260106T060000Z,20260111T060000Z,20260112T060000Z,20260117T060000Z,20260118T060000Z,20260123T060000Z,20260124T060000Z,20260129T060000Z,20260130T060000Z
ShortRRuleSetBuilder:
import { RRule, RRuleSet } from 'rrule'import { ShortRRuleSetBuilder } from 'rrule-by-pattern' const rruleSet = new RRuleSet() rruleSet.rrule(new RRule({ freq: RRule.HOURLY, dtstart: new Date(Date.UTC(2025, 11, 25, 6)), until: new Date(Date.UTC(2025, 11, 30, 18)), interval: 12})) rruleSet.rrule(new RRule({ freq: RRule.DAILY, dtstart: new Date(Date.UTC(2026, 0, 1, 6)), until: new Date(Date.UTC(2026, 0, 30, 6)),})) // Original RRuleSet stringrruleSet.toString()DTSTART:20251225T060000ZRRULE:FREQ=HOURLY;UNTIL=20251230T180000Z;INTERVAL=12DTSTART:20260101T060000ZRRULE:FREQ=DAILY;UNTIL=20260130T060000Z const pattern: Array<0|1> = [1,1,1,1,0,0] const builder = new ShortRRuleSetBuilder( rruleSet, pattern, rruleSet.count()) const newRRuleSet = builder.build() // Built RRuleSet stringnewRRuleSet.toString()DTSTART:20250101T060000ZRRULE:FREQ=YEARLY;UNTIL=20251231T235959Z;BYDAY=MO,TU,WE,TH,FR,SA,SU;BYSETPOS=359,360,362,363DTSTART:20250101T180000ZRRULE:FREQ=YEARLY;UNTIL=20251231T235959Z;BYDAY=MO,TU,WE,TH,FR,SA,SU;BYSETPOS=359,360,362,363DTSTART:20260101T060000ZRRULE:FREQ=YEARLY;UNTIL=20261231T235959Z;BYDAY=MO,TU,WE,TH,FR,SA,SU;BYSETPOS=1,2,3,4,7,8,9,10,13,14,15,16,19,20,21,22,25,26,27,28
Development
rruleByPattern.js is implemented in TypeScript.
To run the code, checkout this repository and run:
$ yarn
To run the tests, run:
$ yarn test
To build the test coverage, run:
$ yarn coverage
To build files for distribution, run:
$ yarn build