rrecur
v2.0.0
Published
Convert between RFC2445 RRULE and its JSON equivalent. Useful with rrule.js.
Downloads
345
Maintainers
Readme
rrecur
Convert between RFC2445 RRULE and its JSON equivalent AND see the future (and past). Useful with rrule.js
.
If you want UIs like these:
Google Calendar: http://imgur.com/a/gT7Af
Thunderbird Calendar: http://imgur.com/a/LhnWU
Kendo Calendar: http://imgur.com/a/zVLyg
You need a schedule-logic library like this to actually interpret RRULE
s and schedule the events.
Usage
parse & stringify
This snippet will work both in the Browser and with Node.js (hence the scary bit at the bottom).
From JSON to RRULE
(function (exports) {
'use strict';
var Rrecur = exports.Rrecur || require('rrecur').Rrecur
, rfcString
;
// every other month on the first and last sunday
rfcString = Rrecur.stringify({
"freq": "monthly"
, "interval": "2"
, "count": "10"
, "byday": ["1su","-1su"]
});
}('undefined' !== typeof exports && exports || new Function('return this')()));
From RRULE to JSON
(function (exports) {
'use strict';
var Rrecur = exports.Rrecur || require('rrecur').Rrecur
, rfcString
, rruleObject
;
rfcString = "RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU";
rruleObject = Rrecur.parse(rfcString);
// Also supports sans-RRULE prefix plus DTSTART for the sake of `rrule.js` compatability
rfcString = "DTSTART=20140616T103000Z;FREQ=DAILY;BYHOUR=10;BYMINUTE=30;BYSECOND=0;UNTIL=20150616T153000Z";
rruleObject = Rrecur.parse(rfcString);
}('undefined' !== typeof exports && exports || new Function('return this')()));
next occurrence of an event
Scenario: I want an alarm to go off every day at 10:30am, given my location.
Since we can't specify timezones with a JavaScript date object, we pretend internally that local time is zoneless time. UTC is handled exactly as UTC.
So let's say it's 8:00am on our server in Utah on the first day of summer and we want to set an alarm for 10:30am in New York (30 minutes from now) every mon, wed, fri:
var rrecur
;
rrecur = Rrecur.create({
dtstart: {
zoneless: Rrecur.toLocaleISOString(new Date(2014,06,21, 10,30,0), "GMT-0400 (EDT)")
// OR utc: new Date(2014,06,21, 10,30,0).toISOString()
, locale: "GMT-0400 (EDT)"
}
, rrule: {
freq: 'daily'
, until: Rrecur.toAdjustedISOString(new Date(2014,06,22, 10,30,0), "GMT-0400 (EDT)")
, count: 1
, byhour: [10]
, byminute: [30]
, byday: ['mo','we','fr'] // Or [Rrecur.weekdays[1], Rrecur.weekdays[3], Rrecur.weekdays[5]]
// `bysecond` will default to 00, since that's what's specified in `dtstart`
}
}, new Date());
rrecur.next(); // 2014-05-21T10:30:00.000-0400
If you didn't specify locale
then you would get back a time in UTC
or in GMT-0600 (MDT)
that you would need to manually adjust.
Whether you specify zoneless
or utc
, you must still specify locale
.
one-time events
var rrecur
;
rrecur = Rrecur.create({
dtstart: {
locale: new Date(2014,06,21, 10,30,0).toString()
}
, rrule: null
}, new Date());
// Assuming you specified the Date on a machine running on MDT
rrecur.next(); // 2014-07-21T16:30:00.000-0000
For one-time events you may simply use a locale string, which will be converted
into to both zoneless
and utc
for internal purposes.
Also, rrule
will be automatically populated to match the zoneless
dtstart.
Installation
browser
NOTE: you only need rrecur.js
for the basic JSON <-> RRULE
conversion.
If you want to actually find the occurances you'll need
underscore.js
, rrule.js
, and moment.js
, and rrecur-iterator.js
.
However, in some future version I may be able to eliminate underscore.js
and rrule.js
.
via bower
bower install rrecur
via download
wget https://raw2.github.com/coolaj86/rrecurjs/master/rrecur.js
wget https://raw2.github.com/coolaj86/rrecurjs/master/rrecur-iterator.js
and insert the script tag, of course
<script src="underscore.js"></script>
<script src="rrule.js"></script>
<script src="moment.js"></script>
<script src="rrecur.js"></script>
<script src="rrecur-iterator.js"></script>
script(src="underscore.js")
script(src="rrule.js")
script(src="moment.js")
script(src="rrecur.js")
script(src="rrecur-iterator.js")
I know, it's a lot of dependencies... but that's just how it is.
In a future version it may be reasonable to drop underscore
and rrule
(or at least substitute lodash
for underscore),
but moment
is a must. JavaScript's Date object is just too messed up.
node.js
npm install rrecur
API
Convert between RFC2445 RRULE and its JSON equivalent.
Rrecur.parse(rruleStr)
- parses a string rrule (allows non-standarddtstart
in string)Rrecur.stringify(rruleObj)
- stringifies an rrule object (allows non-standarddtstart
)
Find the next (or previous) occurence of an event in an rrule chain.
Rrecur.create(rrule, localeDateString)
- creates a wrapped instance fromrrule.js
from an rrule object or stringlocaleDateString
- a string such asWed Jul 16 2014 10:30:00 GMT-0400 (EDT)
Rrecur#previous()
- cycles backwards through time to find a previous instance up todtstart
Rrecur#next()
- cycles forwards through time to find the next instance up tountil
orcount
Utility functions
Rrecur.toLocaleISOString(date, [locale])
- ouput an ISO string with timezone information2014-06-21T10:00:00.000-0600
instead ofSat Jun 21 2014 10:15:08 GMT-0600 (MDT)
or2014-06-21T16:00:00.000Z
- If
locale
is specified in a format such as-04:00
orGMT-0400 (EDT)
, the local (not UTC) time is still used, but the offset is replaced with the supplied locale.
Rrecur.toAdjustedISOString(date, locale)
date
- A local date object (with the wrong timezone)locale
A JavaScript Locale string (or Date string) with the desired timezone- returns a UTC string adjusted to accurately represent the desired timezone
RRULEs
You put in an object like this:
{ "freq": "weekly"
, "until": "2015-01-01T10:30:00.000Z"
, "byday": ["tu", "th"]
, "byhour": [4]
, "byminute": [30]
}
freq
-yearly|monthly|weekly|daily|hourly|minutely|secondly
interval
- bi-weekly, tri-weekly, etcbymonth
byweekno
byyearday
bymonthday
byday
- 0-7, su,mo,tu,we,th,fr,sa,subyhour
byminute
bysecond
until
- seems that this must be given in UTC as per spec, which is weirdcount
- how many occurrenceswkst
- which day the week starts on 0-7, sa,su,mobysetpos
- not sure how this works - http://www.kanzaki.com/docs/ical/recur.htmldtstart
- specifies the first event (or a date close to it), non-standard as part of rrule, but is part of ical- If you don't specify
dtstart
, the current time will be used. - You cannot get
previous()
beforedtstart
- If you don't specify
locale
- specifies the locale in the formatGMT-0500 (EST)
- non-standard, in generaltzid
- specifies the locale, non-standard as part of rrule, but is part of ical
See https://github.com/jkbr/rrule#api for implementation details.
Examples
JSON version of iCal RRULE
{ "freq": "daily"
, "until": "2015-01-01T10:30:00.000Z"
, "byday": ["tu", "th"]
, "byhour": [4]
, "byminute": [30]
}
Non-standard iCal directive
(once TZID
is implemented, this will be standard)
DTSTART;LOCALE=GMT-0500 (EST):20140616T103000
RRULE:FREQ=DAILY;BYHOUR=10;BYMINUTE=30;BYSECOND=0;UNTIL=20150616T153000Z
Non-standard iCal directive (rrule.js
-flavored)
DTSTART=20140616T103000Z;FREQ=DAILY;BYHOUR=10;BYMINUTE=30;BYSECOND=0;UNTIL=20150616T153000Z
Appendix
Because I needed a place to rant.
Timezones
Timezones are a PAIN! Right!?
We take care of the hard brainwork for you, but just so you know:
Here are the problems:
- JavaScript's native Date object has only two options - Locale and UTC
- The server may have a different locale than the client
rrule.js
only operates on Locale - the local time of the serverRRULE
s are zoneless - 10:30am is meant to be in the user's timeDTSTART;TZID=America/New_York
isn't yet supported byrrule.js
Here are solutions:
DTSTART
you can includeLOCALE
(recommended) or use UTC (confusing)UNTIL
you must use UTC (confusing, but that's the way it is)- Try
Rrecur.toAdjustedISOString(new Date(2014,06,16,10,30,00), 'GMT-0600 (MDT)')
- Try
RRULE
s are zoneless, but we do our best to put them in the right zone.- Everything is calculated in local time under the hood.
Remember:
- Always specify RRULEs in local time (except DTSTART and UNTIL in UTC).
- An RRULE for Monday at 10am will fire well after the sun is risen whether in California or China
- An RRULE for Monday at 10am will have a different UTC conversion in California than in China
dtstart
should always be in UTC or in local time with a localeuntil
must be specified in UTC- all calculations will be done in the local time of the server