UNPKG

26.6 kBMarkdownView Raw
1rrule.js
2========
3
4**Library for working with recurrence rules for calendar dates.**
5
6[![NPM version][npm-image]][npm-url]
7[![Build Status][ci-image]][ci-url]
8[![js-standard-style][js-standard-image]][js-standard-url]
9[![Downloads][downloads-image]][downloads-url]
10[![Gitter][gitter-image]][gitter-url]
11[![codecov.io](http://codecov.io/github/jakubroztocil/rrule/coverage.svg?branch=master)](http://codecov.io/github/jakubroztocil/rrule?branch=master)
12
13rrule.js supports recurrence rules as defined in the [iCalendar
14RFC](https://tools.ietf.org/html/rfc5545), with a few important
15[differences](#differences-from-icalendar-rfc). It is a partial port of the
16`rrule` module from the excellent
17[python-dateutil](http://labix.org/python-dateutil/) library. On top of
18that, it supports parsing and serialization of recurrence rules from and
19to natural language.
20
21* * * * *
22
23
24### Quick Start
25
26- [Demo app](http://jakubroztocil.github.io/rrule/)
27
28#### Client Side
29
30```bash
31$ yarn add rrule
32```
33
34Alternatively, download manually:
35
36 * [rrule.min.js](https://jakubroztocil.github.io/rrule/dist/es5/rrule.min.js) (bundled, minified)
37 * [rrule.js](https://jakubroztocil.github.io/rrule/dist/es5/rrule.js) (bundled, not minified)
38 * [rrule-tz.min.js](https://jakubroztocil.github.io/rrule/dist/es5/rrule-tz.min.js) (with timezone support, bundled, minified)
39 * [rrule-tz.js](https://jakubroztocil.github.io/rrule/dist/es5/rrule-tz.js) (with timezone support, bundled, not minified)
40
41```html
42<script src="rrule/dist/es5/rrule.min.js"></script>
43```
44
45#### Server Side
46
47Includes optional TypeScript types
48
49```bash
50$ yarn add rrule
51# or
52$ npm install rrule
53```
54
55#### Usage
56
57**RRule:**
58```es6
59import { RRule, RRuleSet, rrulestr } from 'rrule'
60
61// Create a rule:
62const rule = new RRule({
63 freq: RRule.WEEKLY,
64 interval: 5,
65 byweekday: [RRule.MO, RRule.FR],
66 dtstart: new Date(Date.UTC(2012, 1, 1, 10, 30)),
67 until: new Date(Date.UTC(2012, 12, 31))
68})
69
70// Get all occurrence dates (Date instances):
71rule.all()
72[ '2012-02-03T10:30:00.000Z',
73 '2012-03-05T10:30:00.000Z',
74 '2012-03-09T10:30:00.000Z',
75 '2012-04-09T10:30:00.000Z',
76 '2012-04-13T10:30:00.000Z',
77 '2012-05-14T10:30:00.000Z',
78 '2012-05-18T10:30:00.000Z',
79
80 /* … */]
81
82// Get a slice:
83rule.between(new Date(Date.UTC(2012, 7, 1)), new Date(Date.UTC(2012, 8, 1)))
84['2012-08-27T10:30:00.000Z',
85 '2012-08-31T10:30:00.000Z']
86
87// Get an iCalendar RRULE string representation:
88// The output can be used with RRule.fromString().
89rule.toString()
90"DTSTART:20120201T093000Z\nRRULE:FREQ=WEEKLY;INTERVAL=5;UNTIL=20130130T230000Z;BYDAY=MO,FR"
91
92// Get a human-friendly text representation:
93// The output can be used with RRule.fromText().
94rule.toText()
95"every 5 weeks on Monday, Friday until January 31, 2013"
96```
97
98**RRuleSet:**
99```js
100const rruleSet = new RRuleSet()
101
102// Add a rrule to rruleSet
103rruleSet.rrule(new RRule({
104 freq: RRule.MONTHLY,
105 count: 5,
106 dtstart: new Date(Date.UTC(2012, 1, 1, 10, 30))
107}))
108
109// Add a date to rruleSet
110rruleSet.rdate(new Date(Date.UTC(2012, 6, 1, 10, 30)))
111
112// Add another date to rruleSet
113rruleSet.rdate(new Date(Date.UTC(2012, 6, 2, 10, 30)))
114
115// Add a exclusion rrule to rruleSet
116rruleSet.exrule(new RRule({
117 freq: RRule.MONTHLY,
118 count: 2,
119 dtstart: new Date(Date.UTC(2012, 2, 1, 10, 30))
120}))
121
122// Add a exclusion date to rruleSet
123rruleSet.exdate(new Date(Date.UTC(2012, 5, 1, 10, 30)))
124
125// Get all occurrence dates (Date instances):
126rruleSet.all()
127[ '2012-02-01T10:30:00.000Z',
128 '2012-05-01T10:30:00.000Z',
129 '2012-07-01T10:30:00.000Z',
130 '2012-07-02T10:30:00.000Z' ]
131
132// Get a slice:
133rruleSet.between(new Date(Date.UTC(2012, 2, 1)), new Date(Date.UTC(2012, 6, 2)))
134[ '2012-05-01T10:30:00.000Z', '2012-07-01T10:30:00.000Z' ]
135
136
137 // To string
138rruleSet.valueOf()
139['DTSTART:20120201T023000Z',
140 'RRULE:FREQ=MONTHLY;COUNT=5',
141 'RDATE:20120701T023000Z,20120702T023000Z',
142 'EXRULE:FREQ=MONTHLY;COUNT=2',
143 'EXDATE:20120601T023000Z']
144
145// To string
146rruleSet.toString()
147'["DTSTART:20120201T023000Z","RRULE:FREQ=MONTHLY;COUNT=5","RDATE:20120701T023000Z,20120702T023000Z","EXRULE:FREQ=MONTHLY;COUNT=2","EXDATE:20120601T023000Z"]'
148```
149
150**rrulestr:**
151```js
152// Parse a RRule string, return a RRule object
153rrulestr('DTSTART:20120201T023000Z\nRRULE:FREQ=MONTHLY;COUNT=5')
154
155// Parse a RRule string, return a RRuleSet object
156rrulestr('DTSTART:20120201T023000Z\nRRULE:FREQ=MONTHLY;COUNT=5', {forceset: true})
157
158// Parse a RRuleSet string, return a RRuleSet object
159rrulestr('DTSTART:20120201T023000Z\nRRULE:FREQ=MONTHLY;COUNT=5\nRDATE:20120701T023000Z,20120702T023000Z\nEXRULE:FREQ=MONTHLY;COUNT=2\nEXDATE:20120601T023000Z')
160
161```
162
163### Important: Use UTC dates
164
165Dates in JavaScript are tricky. `RRule` tries to support as much flexibility as possible without adding any large required 3rd party dependencies, but that means we also have some special rules.
166
167By default, `RRule` deals in ["floating" times or UTC timezones](https://tools.ietf.org/html/rfc5545#section-3.2.19). If you want results in a specific timezone, `RRule` also provides [timezone support](#timezone-support). Either way, JavaScript's built-in "timezone" offset tends to just get in the way, so this library simply doesn't use it at all. All times are returned with zero offset, as though it didn't exist in JavaScript.
168
169**The bottom line is the returned "UTC" dates are always meant to be interpreted as dates in your local timezone. This may mean you have to do additional conversion to get the "correct" local time with offset applied.**
170
171For this reason, it is highly recommended to use timestamps in UTC eg. `new Date(Date.UTC(...))`. Returned dates will likewise be in UTC (except on Chrome, which always returns dates with a timezone offset).
172
173For example:
174
175```ts
176// local machine zone is America/Los_Angeles
177const rule = RRule.fromString(
178 "DTSTART;TZID=America/Denver:20181101T190000;\n"
179 + "RRULE:FREQ=WEEKLY;BYDAY=MO,WE,TH;INTERVAL=1;COUNT=3"
180)
181rule.all()
182
183[ 2018-11-01T18:00:00.000Z,
184 2018-11-05T18:00:00.000Z,
185 2018-11-07T18:00:00.000Z ]
186// Even though the given offset is `Z` (UTC), these are local times, not UTC times.
187// Each of these this is the correct local Pacific time of each recurrence in
188// America/Los_Angeles when it is 19:00 in America/Denver, including the DST shift.
189
190// You can get the local components by using the getUTC* methods eg:
191date.getUTCDate() // --> 1
192date.getUTCHours() // --> 18
193```
194
195If you want to get the same times in true UTC, you may do so eg. using Luxon:
196
197```ts
198rule.all().map(date =>
199DateTime.fromJSDate(date)
200 .toUTC()
201 .setZone('local', { keepLocalTime: true })
202 .toJSDate()
203)
204
205[ 2018-11-02T01:00:00.000Z,
206 2018-11-06T02:00:00.000Z,
207 2018-11-08T02:00:00.000Z ]
208// These times are in true UTC; you can see the hours shift
209```
210
211For more examples see
212[python-dateutil](http://labix.org/python-dateutil/) documentation.
213
214* * * * *
215
216### Timezone Support
217
218Optionally, it also supports use of the `TZID` parameter in the
219[RFC](https://tools.ietf.org/html/rfc5545#section-3.2.19)
220when the [Luxon](https://github.com/moment/luxon) library is provided. The
221[specification](https://moment.github.io/luxon/docs/manual/zones.html#specifying-a-zone)
222and [support matrix](https://moment.github.io/luxon/docs/manual/matrix.html) for Luxon apply.
223
224Example with `TZID`:
225
226```js
227new RRule({
228 dtstart: new Date(Date.UTC(2018, 1, 1, 10, 30)),
229 count: 1,
230 tzid: 'Asia/Tokyo'
231}).all()
232
233// assuming the system timezone is set to America/Los_Angeles, you get:
234[ '2018-01-31T17:30:00.000Z' ]
235// which is the time in Los Angeles when it's 2018-02-01T10:30:00 in Tokyo.
236```
237
238Whether or not you use the `TZID` param, make sure to only use JS `Date` objects that are
239represented in UTC to avoid unexpected timezone offsets being applied, for example:
240
241```js
242// WRONG: Will produce dates with TZ offsets added
243new RRule({
244 freq: RRule.MONTHLY,
245 dtstart: new Date(2018, 1, 1, 10, 30),
246 until: new Date(2018, 2, 31)
247}).all()
248
249[ '2018-02-01T18:30:00.000Z', '2018-03-01T18:30:00.000Z' ]
250
251// RIGHT: Will produce dates with recurrences at the correct time
252new RRule({
253 freq: RRule.MONTHLY,
254 dtstart: new Date(Date.UTC(2018, 1, 1, 10, 30)),
255 until: new Date(Date.UTC(2018, 2, 31))
256}).all()
257
258[ '2018-02-01T10:30:00.000Z', '2018-03-01T10:30:00.000Z' ]
259```
260
261### API
262
263#### `RRule` Constructor
264
265```javascript
266new RRule(options[, noCache=false])
267```
268
269The `options` argument mostly corresponds to the properties defined for `RRULE` in the
270iCalendar RFC. Only `freq` is required.
271
272<table>
273 <!-- why, markdown... -->
274 <thead>
275 <tr>
276 <th>Option</th>
277 <th>Description</th>
278 </tr>
279 <thead>
280 <tbody>
281 <tr>
282 <td><code>freq</code></td>
283 <td>
284 <p>(required) One of the following constants:</p>
285 <ul>
286 <li><code>RRule.YEARLY</code></li>
287 <li><code>RRule.MONTHLY</code></li>
288 <li><code>RRule.WEEKLY</code></li>
289 <li><code>RRule.DAILY</code></li>
290 <li><code>RRule.HOURLY</code></li>
291 <li><code>RRule.MINUTELY</code></li>
292 <li><code>RRule.SECONDLY</code></li>
293 </ul>
294 </td>
295 </tr>
296 <tr>
297 <td><code>dtstart</code></td>
298 <td>The recurrence start. Besides being the base for the
299 recurrence, missing parameters in the final recurrence
300 instances will also be extracted from this date. If not
301 given, <code>new Date</code> will be used instead.
302 **IMPORTANT:** See the discussion under <a href="#timezone-support">timezone support</a>
303 </td>
304 </tr>
305 <tr>
306 <td><code>interval</code></td>
307 <td>The interval between each freq iteration. For example,
308 when using <code>RRule.YEARLY</code>, an interval of <code>2</code> means
309 once every
310 two years, but with <code>RRule.HOURLY</code>, it means once every two
311 hours.
312 The default interval is <code>1</code>.
313 </td>
314 </tr>
315 <tr>
316 <td><code>wkst</code></td>
317 <td>The week start day. Must be one of the <code>RRule.MO</code>,
318 <code>RRule.TU</code>, <code>RRule.WE</code> constants, or an integer,
319 specifying
320 the first day of the week. This will affect recurrences based
321 on weekly periods. The default week start is <code>RRule.MO</code>.
322 </td>
323 </tr>
324 <tr>
325 <td><code>count</code></td>
326 <td>How many occurrences will be generated.</td>
327 </tr>
328 <tr>
329 <td><code>until</code></td>
330 <td>If given, this must be a <code>Date</code> instance, that will specify
331 the limit of the recurrence. If a recurrence instance happens
332 to be the same as the <code>Date</code> instance given in the
333 <code>until</code>
334 argument, this will be the last occurrence.
335 </td>
336 </tr>
337 <tr>
338 <td><code>tzid</code></td>
339 <td>If given, this must be a string <a href="https://moment.github.io/luxon/docs/manual/zones.html#specifying-a-zone">supported</a>
340 by Luxon, and the <a href="https://moment.github.io/luxon/">Luxon</a> library must be provided. See
341 discussion under <a href="#timezone-support">Timezone support</a>.
342 </td>
343 </tr>
344 <tr>
345 <td><code>bysetpos</code></td>
346 <td>If given, it must be either an integer, or an array of
347 integers, positive or negative. Each given integer will specify
348 an occurrence number, corresponding to the nth occurrence of
349 the rule inside the frequency period. For example, a
350 <code>bysetpos</code> of <code>-1</code> if combined with a <code>RRule.MONTHLY</code>
351 frequency, and a byweekday of (<code>RRule.MO</code>, <code>RRule.TU</code>,
352 <code>RRule.WE</code>, <code>RRule.TH</code>, <code>RRule.FR</code>), will result in
353 the last
354 work day of every month.
355 </td>
356 </tr>
357 <tr>
358 <td><code>bymonth</code></td>
359 <td>If given, it must be either an integer, or an array of
360 integers, meaning the months to apply the recurrence to.
361 </td>
362 </tr>
363 <tr>
364 <td><code>bymonthday</code></td>
365 <td>If given, it must be either an integer, or an array of
366 integers, meaning the month days to apply the recurrence to.
367 </td>
368 </tr>
369 <tr>
370 <td><code>byyearday</code></td>
371 <td>If given, it must be either an integer, or an array of
372 integers, meaning the year days to apply the recurrence to.
373 </td>
374 </tr>
375 <tr>
376 <td><code>byweekno</code></td>
377 <td>If given, it must be either an integer, or an array of
378 integers, meaning the week numbers to apply the recurrence to.
379 Week numbers have the meaning described in ISO8601, that is,
380 the first week of the year is that containing at least four
381 days of the new year.
382 </td>
383 </tr>
384 <tr>
385 <td><code>byweekday</code></td>
386 <td>If given, it must be either an integer (<code>0 == RRule.MO</code>), an
387 array of integers, one of the weekday constants
388 (<code>RRule.MO</code>,
389 <code>RRule.TU</code>, etc), or an array of these constants. When
390 given,
391 these variables will define the weekdays where the recurrence
392 will be applied. It's also possible to use an argument n for
393 the weekday instances, which will mean the nth occurrence of
394 this weekday in the period. For example, with
395 <code>RRule.MONTHLY</code>,
396 or with <code>RRule.YEARLY</code> and <code>BYMONTH</code>, using
397 <code>RRule.FR.nth(+1)</code> or <code>RRule.FR.nth(-1)</code> in <code>byweekday</code>
398 will specify the first or last friday of the month where the
399 recurrence happens.
400 Notice
401 that the RFC documentation, this is specified as <code>BYDAY</code>,
402 but was renamed to avoid the ambiguity of that argument.
403 </td>
404 </tr>
405 <tr>
406 <td><code>byhour</code></td>
407 <td>If given, it must be either an integer, or an array of
408 integers, meaning the hours to apply the recurrence to.
409 </td>
410 </tr>
411 <tr>
412 <td><code>byminute</code></td>
413 <td>If given, it must be either an integer, or an array of
414 integers, meaning the minutes to apply the recurrence to.
415 </td>
416 </tr>
417 <tr>
418 <td><code>bysecond</code></td>
419 <td>If given, it must be either an integer, or an array of
420 integers, meaning the seconds to apply the recurrence to.
421 </td>
422 </tr>
423 <tr>
424 <td><code>byeaster</code></td>
425 <td>This is an extension to the RFC specification which the Python
426 implementation provides.
427 <strong>Not implemented in the JavaScript version.</strong>
428 </td>
429 </tr>
430 </tbody>
431</table>
432
433
434`noCache`: Set to `true` to disable caching of results. If you will use the
435same rrule instance multiple times, enabling caching will improve the
436performance considerably. Enabled by default.
437
438See also [python-dateutil](http://labix.org/python-dateutil/)
439documentation.
440
441
442* * * * *
443
444
445#### Instance properties
446
447<dl>
448 <dt><code>rule.options</code></dt>
449 <dd>Processed options applied to the rule. Includes default options
450 (such us <code>wkstart</code>). Currently,
451 <code>rule.options.byweekday</code> isn't equal
452 to <code>rule.origOptions.byweekday</code> (which is an inconsistency).
453 </dd>
454 <dt><code>rule.origOptions</code></dt>
455 <dd>The original <code>options</code> argument passed to
456 the constructor.</dd>
457</dl>
458
459
460* * * * *
461
462
463#### Occurrence Retrieval Methods
464
465##### `RRule.prototype.all([iterator])`
466
467Returns all dates matching the rule. It is a replacement for the
468iterator protocol this class implements in the Python version.
469
470As rules without `until` or `count` represent infinite date series, you
471can optionally pass `iterator`, which is a function that is called for
472each date matched by the rule. It gets two parameters `date` (the `Date`
473instance being added), and `i` (zero-indexed position of `date` in the
474result). Dates are being added to the result as long as the iterator
475returns `true`. If a `false`-y value is returned, `date` isn't added to
476the result and the iteration is interrupted (possibly prematurely).
477
478```javascript
479rule.all()
480[ '2012-02-01T10:30:00.000Z',
481 '2012-05-01T10:30:00.000Z',
482 '2012-07-01T10:30:00.000Z',
483 '2012-07-02T10:30:00.000Z' ]
484
485rule.all(function (date, i){return i < 2})
486[ '2012-02-01T10:30:00.000Z',
487 '2012-05-01T10:30:00.000Z' ]
488```
489
490##### `RRule.prototype.between(after, before, inc=false [, iterator])`
491
492Returns all the occurrences of the rrule between `after` and `before`.
493The inc keyword defines what happens if `after` and/or `before` are
494themselves occurrences. With `inc == true`, they will be included in the
495list, if they are found in the recurrence set.
496
497Optional `iterator` has the same function as it has with
498`RRule.prototype.all()`.
499
500```javascript
501rule.between(new Date(Date.UTC(2012, 7, 1)), new Date(Date.UTC(2012, 8, 1)))
502['2012-08-27T10:30:00.000Z',
503 '2012-08-31T10:30:00.000Z']
504```
505
506##### `RRule.prototype.before(dt, inc=false)`
507
508Returns the last recurrence before the given `Date` instance. The `inc`
509argument defines what happens if `dt` is an occurrence. With
510`inc == true`, if `dt` itself is an occurrence, it will be returned.
511
512
513##### `RRule.prototype.after(dt, inc=false)`
514
515Returns the first recurrence
516after the given `Date` instance. The `inc` argument defines what happens
517if `dt` is an occurrence. With `inc == true`, if `dt` itself is an
518occurrence, it will be returned.
519
520See also [python-dateutil](http://labix.org/python-dateutil/)
521documentation.
522
523
524* * * * *
525
526
527#### iCalendar RFC String Methods
528
529##### `RRule.prototype.toString()`
530
531Returns a string representation of the rule as per the iCalendar RFC.
532Only properties explicitly specified in `options` are included:
533
534```javascript
535rule.toString()
536"DTSTART:20120201T093000Z\nRRULE:FREQ=WEEKLY;INTERVAL=5;UNTIL=20130130T230000Z;BYDAY=MO,FR"
537
538rule.toString() == RRule.optionsToString(rule.origOptions)
539true
540```
541
542##### `RRule.optionsToString(options)`
543
544Converts `options` to iCalendar RFC `RRULE` string:
545
546```javascript
547// Get full a string representation of all options,
548// including the default and inferred ones.
549RRule.optionsToString(rule.options)
550"DTSTART:20120201T093000Z\nRRULE:FREQ=WEEKLY;INTERVAL=5;WKST=0;UNTIL=20130130T230000Z;BYDAY=MO,FR;BYHOUR=10;BYMINUTE=30;BYSECOND=0"
551
552// Cherry-pick only some options from an rrule:
553RRule.optionsToString({
554 freq: rule.options.freq,
555 dtstart: rule.options.dtstart
556})
557"DTSTART:20120201T093000Z\nRRULE:FREQ=WEEKLY;"
558```
559
560##### `RRule.fromString(rfcString)`
561
562Constructs an `RRule` instance from a complete `rfcString`:
563
564```javascript
565var rule = RRule.fromString("DTSTART:20120201T093000Z\nRRULE:FREQ=WEEKLY;")
566
567// This is equivalent
568var rule = new RRule(RRule.parseString("DTSTART:20120201T093000Z\nRRULE:FREQ=WEEKLY"))
569```
570
571##### `RRule.parseString(rfcString)`
572
573Only parse RFC string and return `options`.
574
575```javascript
576var options = RRule.parseString('FREQ=DAILY;INTERVAL=6')
577options.dtstart = new Date(Date.UTC(2000, 1, 1))
578var rule = new RRule(options)
579```
580
581* * * * *
582
583#### Natural Language Text Methods
584
585These methods provide an incomplete support for text–`RRule` and
586`RRule`–text conversion. You should test them with your input to see
587whether the result is acceptable.
588
589##### `RRule.prototype.toText([gettext, [language]])`
590
591Returns a textual representation of `rule`. The `gettext` callback, if
592provided, will be called for each text token and its return value used
593instead. The optional `language` argument is a language definition to be
594used (defaults to `rrule/nlp.js:ENGLISH`).
595
596```javascript
597var rule = new RRule({
598 freq: RRule.WEEKLY,
599 count: 23
600})
601rule.toText()
602"every week for 23 times"
603```
604
605##### `RRule.prototype.isFullyConvertibleToText()`
606
607Provides a hint on whether all the options the rule has are convertible
608to text.
609
610##### `RRule.fromText(text[, language])`
611
612Constructs an `RRule` instance from `text`.
613
614```javascript
615rule = RRule.fromText('every day for 3 times')
616```
617
618##### `RRule.parseText(text[, language])`
619
620Parse `text` into `options`:
621
622```javascript
623options = RRule.parseText('every day for 3 times')
624// {freq: 3, count: "3"}
625options.dtstart = new Date(Date.UTC(2000, 1, 1))
626var rule = new RRule(options)
627```
628
629
630* * * * *
631
632#### `RRuleSet` Constructor
633
634```javascript
635new RRuleSet([noCache=false])
636```
637
638The RRuleSet instance allows more complex recurrence setups, mixing multiple
639 rules, dates, exclusion rules, and exclusion dates.
640
641Default `noCache` argument is `false`, caching of results will be enabled,
642improving performance of multiple queries considerably.
643
644##### `RRuleSet.prototype.rrule(rrule)`
645
646Include the given rrule instance in the recurrence set generation.
647
648##### `RRuleSet.prototype.rdate(dt)`
649Include the given datetime instance in the recurrence set generation.
650
651##### `RRuleSet.prototype.exrule(rrule)`
652Include the given rrule instance in the recurrence set exclusion list. Dates
653which are part of the given recurrence rules will not be generated, even if
654some inclusive rrule or rdate matches them. NOTE: EXRULE has been (deprecated
655in RFC 5545)[https://icalendar.org/iCalendar-RFC-5545/a-3-deprecated-features.html]
656and does not support a DTSTART property.
657
658##### `RRuleSet.prototype.exdate(dt)`
659Include the given datetime instance in the recurrence set exclusion list. Dates
660included that way will not be generated, even if some inclusive rrule or
661rdate matches them.
662
663##### `RRuleSet.prototype.tzid(tz?)`
664Sets or overrides the timezone identifier. Useful if there are no rrules in this
665RRuleSet and thus no DTSTART.
666
667##### `RRuleSet.prototype.all([iterator])`
668
669Same as `RRule.prototype.all`.
670
671##### `RRuleSet.prototype.between(after, before, inc=false [, iterator])`
672
673Same as `RRule.prototype.between`.
674
675##### `RRuleSet.prototype.before(dt, inc=false)`
676
677Same as `RRule.prototype.before`.
678
679##### `RRuleSet.prototype.after(dt, inc=false)`
680
681Same as `RRule.prototype.after`.
682
683##### `RRuleSet.prototype.rrules()`
684
685Get list of included rrules in this recurrence set.
686
687##### `RRuleSet.prototype.exrules()`
688
689Get list of excluded rrules in this recurrence set.
690
691##### `RRuleSet.prototype.rdates()`
692
693Get list of included datetimes in this recurrence set.
694
695##### `RRuleSet.prototype.exdates()`
696
697Get list of excluded datetimes in this recurrence set.
698
699* * * * *
700
701#### `rrulestr` Function
702
703```js
704rrulestr(rruleStr[, options])
705```
706
707The `rrulestr` function is a parser for RFC-like syntaxes. The string passed
708as parameter may be a multiple line string, a single line string, or just the
709RRULE property value.
710
711Additionally, it accepts the following keyword arguments:
712
713`cache`
714If True, the rruleset or rrule created instance will cache its results.
715Default is not to cache.
716
717`dtstart`
718If given, it must be a datetime instance that will be used when no DTSTART
719property is found in the parsed string. If it is not given, and the property
720is not found, datetime.now() will be used instead.
721
722`unfold`
723If set to True, lines will be unfolded following the RFC specification. It
724defaults to False, meaning that spaces before every line will be stripped.
725
726`forceset`
727If set to True a rruleset instance will be returned, even if only a single rule
728is found. The default is to return an rrule if possible, and an rruleset if necessary.
729
730`compatible`
731If set to True, the parser will operate in RFC-compatible mode. Right now it
732means that unfold will be turned on, and if a DTSTART is found, it will be
733considered the first recurrence instance, as documented in the RFC.
734
735`tzid`
736If given, it must be a string that will be used when no `TZID` property is found
737in the parsed string. If it is not given, and the property is not found, `'UTC'`
738will be used by default.
739
740
741* * * * *
742
743### Differences From iCalendar RFC
744
745* `RRule` has no `byday` keyword. The equivalent keyword has been replaced by
746the `byweekday` keyword, to remove the ambiguity present in the original
747keyword.
748* Unlike documented in the RFC, the starting datetime, `dtstart`, is
749not the first recurrence instance, unless it does fit in the specified rules.
750This is in part due to this project being a port of
751[python-dateutil](https://labix.org/python-dateutil#head-a65103993a21b717f6702063f3717e6e75b4ba66),
752which has the same non-compliant functionality. Note that you can get the
753original behavior by using a `RRuleSet` and adding the `dtstart` as an `rdate`.
754
755```javascript
756var rruleSet = new RRuleSet()
757var start = new Date(Date.UTC(2012, 1, 1, 10, 30))
758
759// Add a rrule to rruleSet
760rruleSet.rrule(new RRule({
761 freq: RRule.MONTHLY,
762 count: 5,
763 dtstart: start
764}))
765
766// Add a date to rruleSet
767rruleSet.rdate(start)
768```
769
770* Unlike documented in the RFC, every keyword is valid on every frequency (the
771RFC documents that `byweekno` is only valid on yearly frequencies, for example).
772
773### Development
774
775rrule.js is implemented in Typescript. It uses [JavaScript Standard Style](https://github.com/feross/standard) coding style.
776
777To run the code, checkout this repository and run:
778
779```
780$ yarn
781```
782
783To run the tests, run:
784
785```
786$ yarn test
787```
788
789To build files for distribution, run:
790
791```
792$ yarn build
793```
794
795#### Authors
796
797* [Jakub Roztocil](http://roztocil.co/)
798 ([@jakubroztocil](http://twitter.com/jakubroztocil))
799* Lars Schöning ([@lyschoening](http://twitter.com/lyschoening))
800* David Golightly ([@davigoli](http://twitter.com/davigoli))
801
802Python `dateutil` is written by [Gustavo
803Niemeyer](http://niemeyer.net/).
804
805See [LICENCE](https://github.com/jakubroztocil/rrule/blob/master/LICENCE) for
806more details.
807
808[npm-url]: https://npmjs.org/package/rrule
809[npm-image]: http://img.shields.io/npm/v/rrule.svg
810
811[ci-url]: https://github.com/jakubroztocil/rrule/actions
812[ci-image]: https://github.com/jakubroztocil/rrule/workflows/Node%20CI/badge.svg
813
814[downloads-url]: https://npmjs.org/package/rrule
815[downloads-image]: http://img.shields.io/npm/dm/rrule.svg?style=flat-square
816
817[js-standard-url]: https://github.com/feross/standard
818[js-standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat
819
820[gitter-url]: https://gitter.im/rrule-js/Lobby
821[gitter-image]: https://img.shields.io/gitter/room/nwjs/nw.js.svg
822
823
824#### Related projects
825
826* https://rrules.com/ — RESTful API to get back occurrences of RRULEs that conform to RFC 5545.
827