Category Archives: Ical RFC5545 / 2445

Notes on working with the icalendar spec:http://www.ietf.org/rfc/rfc5545.txt
(RFC2445 spec is obsolete)
More readable format here using old spec: http://www.kanzaki.com/docs/ical/

Correct Handling of UID, RECURRENCE-ID, SEQUENCE

Some folks have been using the free version of this plugin for several years.  Some of them have recurring events with modified instances.  Sometimes the frequency of modifications is high.   In the last few months this has caused a fair bit of extra support required as anomalies crop up.  Sometimes bugs are flushed out and sometimes almost unanswerable questions are raised as to what the plugin should do if it gets weird data.

The point of this post is to highlight some of the complexities that may develop and urge you to keep your ics files as clean as possible or use amr-events where it is possible to delete old events (hard to delete volumes of old events in google calendar).

An example is modifications to recurring rules or rdates and modifications to instances of those recurring rules (themselves already a modification.)

For example:Assume we have a recurring event.  It starts with a SEQUENCE: 0

DTSTART;VALUE=DATE:20140421
 RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=3MO
 UID:1f4irrb5uh6q3cdfsnq15vd00g_R20140421@google.com
 SEQUENCE:0

This generates an infinite set of mondays, including the following

  • 19th May
  • 16th June
  • 21 July
  • 18 August
  • etc

Now, one of the instances gets modified.  (This could be just the description or the actual date.)  A RECURRENCE-ID VEVENT is created for each instance modification and the SEQUENCE NO is updated.   The recurrence-id matches the date in the recurring rule that it applies to. The combination of UID, RECURRENCE-ID and SEQUENCE helps us identify the instance that is being updated.

For a given pair of "UID" and "SEQUENCE" property values,
   the "RECURRENCE-ID" value for a recurrence instance is fixed.
DTSTART;VALUE=DATE:20140721  (ie no date change in this example)
 DTSTAMP:20140720T064853Z
 UID:1f4irrb5uh6q3cdfsnq15vd00g_R20140421@google.com
 RECURRENCE-ID;VALUE=DATE:20140721

Now assume the original RRULE is modified too, perhaps just the description or shock horror, the recurring date definition?  It’s sequence-no is updated too BUT now what should happen to the RECURRENCE-ID instance?  Should it be updated to indicate it is still valid?  IE we now have:

  • generated date 21 July 2014 with UID and SEQUENCE = 3 and
  • RECURRENCE-ID;VALUE=DATE:20140721 with matching UID and SEQUENCE = 3

It appears that perhaps SEQUENCE numbers can increment separately, so one could conceivably receive a file with a RRULE with an equal to or  greater sequence number than a RECURRENCE-ID.       From   this discussion, it is really not clear what the supplying calendar application will do:

Once UID 1/SEQUENCE 0 hits UID 1/SEQUENCE 1 (which would
mean something significant about the set of instances
has changed) all bets are off in regards to RECURRENCE-ID
values that previously existed.

If the UID/RECURRENCE-ID/SEQUENCE matches a generated date from the rrule with same SEQUENCE (ie both have been modified), then what?  One cannot just use eg: LAST-MODIFIED:20140620T200327Z.  Who is to say that a mod of the RRULE was intended to overwrite the RECURRENCE instance?   Quite possibly not.

What does the plugin do:

For now (until further authoritative input to the contrary), the plugin will assume that a recurring instance (RECURRENCE-ID) in the file is intended to be still there.  It will include the highest sequence number of the recurrence (even if the originating rrule is not there -an  error in supplying application).  Similarly it will include the recurrence even if the rrule does not have a matching date.

It will also assume that the recurrence instance overwrites the RRULE definition even if the RRULE  has a later SEQUENCE number.   The Plugin does not have to worry about the complications of syncing for now.

If you are ever struggling to figure out what the plugin has done. Create a test list and include the RECURRENCE-ID and SEQUENCE fields.  You can reference the test lits by adding ?listtype=x to your events page url.

list showing recurrence-id and sequence
list showing recurrence-id and sequence

Some lengthy related discussions here and in other parts of the thread:

Complications that urge one to keep events as simple as possible:

Searching the web seems to indicate some folks believe RECURRENCE-IDS should not change.  So should we assume that if the RECURRENCE-ID vevent is still in the file then it is still valid and should be included.  (What does this mean for syncing and deletions?  IE How does one ‘delete’ an existing event.  Or should one always delete events from an ics file and reload ONLY what’s in the ics file?)

Dates, Times, Formatting

There are a number of date and time options for you to choose when displaying your events.    The main ones you should be using are created by the plugin and will be formatted by the date and time settings you have specified in the plugin settings (and applying any localisation that may be available in your wordpress setup).  You can specify these by listtype, so say a widget could have a very compact date format and a full list may be more detailed.

screnshot Date Time Formats
Date Time Format settings by listtype

Event date fields formatted by your date settings:

  • EventDate: Mon, June 23, 2014
  • EndDate: Mon, June 30, 2014 (only if event greater than one day)

Event time fields formatted by your time settings:

  • StartTime: 9:00 am
  • EndTime: 10:00 am

Note there may be situations where there is no end time or no end date (eg: if there is no duration or the end date is the same as the start date.   If a field has not been populated, it will not be displayed and neither will any ‘before’ or ‘after’ text.

Field from the ics specification that may be useful.

Formatted using human language function

  • DURATION:1 week , 1 hour

Other date fields in the ‘edit events’ admin screen

screenshot of show screen options in edit events
show screen options in edit events
  • Last 20140630

The ‘last’ date shown in the edit events admin screen shows the last recurrence date of an event.  It is used to select events within a date range (ie exclude events whose recurrences are in the past, without having to rebuild the recurrence logic).  It is also used to sort events in the admin screen by this last recurrence.   It is therefore formatted yyyymmdd for the sorting.   It is not intended to be displayed elsewhere.

Technical fields

These are direct from the ics specification formatted by the DateTime settings  in the plugin settings.   Note the DTEND has a special definition in the ics specification for all day events (it will have the next day as the end date) and may be confusing to normal users.   Some ics generators get the DTEND logic wrong, so this plugin tries to work with duration just in case.

  • DTEND: Mon, June 30, 2014 10:00 am
  • DTSTART: Mon, June 23, 2014 9:00 am

Other fields

As these are very technical, precise fields, they are by default not formatted but left as found.

  • DTSTAMP: 20140616T021842Z
    • the date and time that the instance of the iCalendar object was created.
  • LAST-MODIFIED:20140616T025756Z
    • the date and time last modified – works with the sequence number to determine the latest modification to an event instance.

Html in descriptions in ics feed generation

What to do about html in event descriptions?

Some applications will cope with the html, but there are other applications which do not. EG: Google calendar – does not faciliate html nor  issue it in feed.

HTML in the description field is not explicitly forbidden, however it is probably not recommended.  There is some provision for html to be explicitly allowed for, either:

  •  in the description using an ALTREP parameter,
  • or in an ‘experiemental’  X field, X-ALT-DESC,

WordPress allows us to create events with html in them.  So what to do when the ics feed is generated?

Retaining the html – two possibilties:

Link to the html representation:

DESCRIPTION;ALTREP="http://www.example.com/somepath/":This is an example description.

Provide separate field with html representation:

Outlook will recognise:

X-ALT-DESC;FMTTYPE=text/html:<p>This is an example description.</p>

 

This update does both, as well of course ,as stripping the html from the description field in the ics file.  This means images will be stripped too (only for the feed – do not panic!)

More information for the technically minded

 

 

Problem with Dates/Time – Off by 1 Hour?

If you are using amr-events or amr-ical-events-list you will not have this problem!

Every time a zone somewhere in the world kicks on to daylight saving or off for that matter, I see a bunch of support questions popping up about their event times being off by an hour.    (I monitor wordpress support, stackexchange and wpquestions, and maybe a few more…..)

From a favourite cartoon source - thanks http://xkcd.com/673/

Imagine the confusion this can cause where clients may have subscribed to calendar feeds and have the wrong times.

PHP datetime objects and functions

If people are very lucky, the plugin that they are using has some good coding and is using php DateTime objects with timezone support, and the only problem is that their wordpress timezone is set as a GMT offset, not as a timezone.

That is easily fixed! (goto wordpress general settings)

However all too often the plugin developer has failed to appreciate

  • the complexities of times around the world,
  • timezones,
  • daylight saving and
  • most importance of managing recurring events in one timezone for a display in another where one zone changes daylight saving.  Very easy to generate the wrong times for a recurring event without realising it!
  • even worse governments sometimes change the date/time of the switchover (ok not that often, but it does happen, and then you hope your php installation gets updated with the timezone definitions)

Fixes:

If it is not a simple wordpress timezone setting, then these things are NOT easy to fix and will involve changes to code:

  1. Change to use php DateTime Classes for all date logic .If they are using unix time and not  php datetime objects, it is almost impossible to get it right.  It’s a fairly major rewrite to change all date logic to use the DateTime objects and functions.
  2. If already using, it maybe that the intricacies of recurring event logic have won out.  See below for logic help.

Developers and event website managers should read:

 

 

Need to know the possible combinations for repeating dates? – an Ical cheatsheet

The ical specification allows one to define some very interesting and complicated date recurrences.  This table (adapted from rfc-archive.org/getrfc.php?rfc=5545) was very useful when I decided to rewrite the recurrence engine part of my plugins.

Sorry about the table width – got to get that theme css fixed!

Yearly Monthly Weekly Daily Hourly Minutely Secondly
BY MONTH (1 to 31,  -1 to -31) Expand Limit Limit Limit Limit Limit Limit
BY WEEK NO (1 to 53, -1 to 53) Expand invalid invalid invalid invalid invalid invalid
BY YEAR DAY (1  to 366, -1 to -366) Expand invalid invalid invalid Limit Limit Limit
BY MONTH DAY (1 to 31, -1 to -31) Expand Expand invalid Limit Limit Limit Limit
BY DAY (MO, TU , WE, TH, FR, SA, SU) Note 2 Note 1 Expand Limit Limit Limit Limit
BY HOUR (-23 to 0 to +23) Expand Expand Expand Expand Limit Limit Limit
BY MINUTE (-59 to 0 to 59) Expand Expand Expand Expand Expand Limit Limit
BY SECOND (-60 to 0 to 60) Expand Expand Expand Expand Expand Expand Limit
BY SET POS (-366 to -1,1 to 366) Limit Limit Limit Limit Limit Limit Limit

The “By”‘s are applied in the order indicated. Limit means that the possible repeat dates are limited by the “BY” specification.  Expand means that the possible repeat dates are expanded by the BY values.  The start date will fill in any missing year, month, day, hour, minute or second values.  See the RFC 5545 Specification for examples.

Note 1:

  • Limit the dates if BYMONTHDAY is present;
  • else special expand for monthly

Note2:

  • Limit if BYYEARDAY or BYMONTHDAY is present; otherwise,
  • special expand for WEEKLY if BYWEEKNO present; otherwise,
  • special expand for MONTHLY if BYMONTH present; otherwise,
  • special expand for YEARLY

What every developer ought to know about timezones wrt calendar files

A timezone definition consists of

  • a ID
  • a name
  • a standard time definition with a gmt offset
  • daylight saving time definitions with a series of daylight saving transitions (as rules have changed over time

Ideally every system around the world should be using the same definition of timezones.  However not all systems are kept up to date when a government decides to change a transition time.  In addition not all systems use the same naming conventions, so while to the human it may be obvious which timezone is being referred to, a program has to do some deductions.

Most calendar applications appear to use the olson database or similar.  Windows PC take a slightly different approach, with a requested time change on the first reboot after daylight saving change.  Windows based application issue different timezone ID’s.

A calendar application can decide on it’s own timezone id’s. They have to include the definition (The VTIMEZONE) with the daylight saving changes in the file, however this can be their own version of the timezone definition

What if the issuing application has an outdated version of the daylight saving changes?  Would you not rather control it on your server than taking their definition?

Global Timezone Database

Php, WordPress, Google, Linux (Ubuntu), Apple

These all appear to use the timezone database aka Olson Database.  It has timezone identifiers like:

Australia/Sydney

Fbcal.com

A few months ago, Issued no TZID, no VTIMEZONE, all dates local / floating and just this : X-WR-TIMEZONE;VALUE=TEXT:Europe/Oslo

Mozilla sometimes has great fun confusing people:

DTSTART;TZID=/mozilla.org/20050126_1/America/Denver:20070101T090000

Artistdata.com

Recently I dealt with an ics file that had no TZID, no VTIMEZONE, all dates local / floating

Microsoft Windows PC, Microsoft Exchange

Setting TimeZone in Windows Vista

Microsoft exchange, Windows PC’s and by extension any application that runs on the PC that uses the windows timezones does the gmt offset thing

(GMT+10:00) Canberra, Melbourne, Sydney.

Now Sydney has daylight saving, so we are only GMT+10 for half the year.  The rest of the time we are GMT+11.  If we happen to choose the GMT+11 option for our setup thinking it was more correct we would be wrong…..

What windows does is technically not wrong.  They acknowledge the daylight saving and you can choose to have it automatically update… WHEN you REBOOT the PC, the times will update.

It is however potentially misleading, unnecessarily so.  Particularly around the actual daylight saving change, errors may occur, due

  • an ‘old’ ics file perhaps – the one issued before the times were updated ?, or
  • to applications not always handling the timezone  correctly – It would be very tempting as a programmer to grab that GMT+10 and use that.  Just google things like my meeting is one hour out etc to get a feeling for the problem.

What does this mean for developers using calendar files?

Well it depends a bit on the application issuing the ics file.  You could have to deal with any of these timezone values:

Examples:

  • TZID:America/New_York
  • DTSTART;TZID=”America/New_York”:20080807T090000
  • X-WR-TIMEZONE:Europe/London
  • TZID:Europe/London
  • DTSTART;TZID=Europe/London:20060707T130000
  • TZID:Canberra\, Melbourne\, Sydney
  • DTSTART;TZID=”Canberra, Melbourne, Sydney”:20100831T210000
  • X-WR-TIMEZONE;VALUE=TEXT:Europe/Oslo
  • DTSTART;TZID=”(GMT+01.00) Amsterdam / Berlin / Bern / Rome / Stockholm / Vienna”:20100831T16000
  • TZID:(GMT+02.00) Harare/Pretoria
  • DTSTART;TZID=US/Central:20080726T190000
  • DTSTART;TZID=/mozilla.org/20050126_1/America/Cancun:20070101T090000
  • DTSTART;TZID=”(GMT) Greenwich Mean Time – Dublin / Edinburgh / Lisbon /
  • TZID:/mozilla.org/20050126_1/Pacific/Yap

Windows – assessed using Windows Calendar

Windows Calendar Ics file

Windows calendar defines the TZID with a VTIMEZONE definition

TZID:Canberra\, Melbourne\, Sydney
BEGIN:STANDARD
...
TZNAME:AUS Eastern Standard Time...

and then uses it in the ics file

DTSTART;TZID="Canberra, Melbourne, Sydney":20100831T210000

This is correct according to the spec and not too hard to deal with.    The developer can grab each city and check for a matching timezone on their host system.

A minor gripe is that if you import this into Google and then share the resulting google calendar file, Google will decide to go with Melbourne, even if the rest of your calendars are Sydney.  This may offend some. ;-)

Zimbra

I’m told that Zimbra issues ics files with :

DTSTART;TZID="(GMT+01.00) Amsterdam / Berlin / Bern / Rome / Stockholm / Vienna":20100831T160000

I don’t know whether a VTIMEZONE was included or not.  AS noted before grabbing that GMT+01 may cause incorrect times when daylight saving is involved.

At the very least the reading application  has to deal with that somehow. Possibly by tossing the GMT parts away and looking for the cities again.  My events plugin will do this in the next upgrade

Mozilla / Thunderbird

Mozilla plays nicely (with php anyway!)

PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Australia/Sydney
...
DTSTART;TZID=Australia/Sydney:20100901T170000

Reading the VTIMEZONE definition?

Somehow working with the timezone definition passed in the ics file – Is this an option ? – well maybe – I shudder to think how though. Imagine the confusion if some dates in your website knew about one set of daylight saving and others were obeying the possibly different definition in the ics file. PHP encourages us to use it’s timezone definitions. It has functions to do a variety of timezone functions, but uploading daylight saving changes into a timezone object is not one of them. (Probably a good idea too).

Parsing Timezone Ids

If you are developing an ical parser, I believe that the best approach (wrt correctness and usability) is

  1. attempt to determine the desired timezone from the TZ id (toss those GMT’s if you have too)
  2. match to a timezone identifier that is already in your system, and then use those consistent daylight saving changes
  3. and of course use the DateTime object class – do not mess around with unix time that breaks on old dates.
    Dates, Times, Timezones, daylight saving etc are so fraught with danger (see the best of dates, the worst of dates), that one must use pre-tested logic as much as possible, and there are some very useful functions there.

My amr-ical-events-list plugin

For the record, my plugin will attempt to cope with all of these variations (and more if anyone tells me about them).   If we can extract some city names, it should be easy to match it at least one to the php timezones:

  • explode the names out, stripping off all the quotes, slashes etc
  • If a timezone has been specified in the shortcode, and it matches the city name, then it will deduce that is the timezone
  • If the wordpress timezone  matches the city name, then it will deduce that that is the timezone
  • Else if will attempt to find a match in the php timezone names list (which it should unless something really weird is going on)
  • Else if all that fails, it will just use the wordpress timezone as the base timezone for the events.

Extract From http://tools.ietf.org/html/rfc5545

This property parameter specifies a text value that uniquely identifies the “VTIMEZONE” calendar component to be used when evaluating the time portion of the property. The value of the “TZID” property parameter will be equal to the value of the “TZID” property for the matching time zone definition. An individual “VTIMEZONE” calendar component MUST be specified for each unique “TZID” parameter value specified in the iCalendar object.

Failure to include and follow VTIMEZONE definitions in iCalendar objects may lead to inconsistent understanding of the local time at any given location

The presence of the SOLIDUS character “/” as a prefix, indicates that this “TZID” represents a unique ID in a globally defined time zone registry (when such registry is defined).

Note: This document does not define a naming convention for time zone identifiers. Implementers may want to use the naming conventions defined in existing time zone specifications such as the public-domain TZ database [TZDB]. The specification of globally unique time zone identifiers is not addressed by this document and is left for future study.

Do you need BYYEARDAY for your events?

Is BYYEARDAY useful enough ?

ByYearDay allows the user to enter days of the year to repeat separated by commas (1,2,…366,-366,-365…-1). Almost every real example can be represented in a more user friendly fashion using other ‘BY’s such as BYMONTH and BYMONTHDAY

An example: RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU;BYYEARDAY=72

Only leap years affect whether the 72nd day of the year is 31+28+13 = March 13 or 31+29+12 = March 12. It’s just not useful enough to schedule a meeting on “March 13, except March 12 if it’s a leap year” and that kind of use case can be worked around. (One special case might be to state that a RRULE that occured yearly on Feb 29 might automatically recur on Feb 28 if not a leap year). Without BYYEARDAY we’d see rules like “RRULE:FREQ=YEARLY; INTERVAL=1″ and the date would be March 12 every year.

For this reason, at launch, the amr events plugin does not offer a BYYEARDAY entry option on the edit event screen. It will however read BYYEARDAY’s entered in ics files and apply the necessary recurrence rule and included in any calendar listing.

Does your group need BYYEARDAY ?

If your website needs to be able to offer entry of recurring dates using BYYEARDAY for it’s members, it will be easy to add.  It is beingexcluded to avoid cluttering the screen unnecessarily.

The last week of the year is….

According to wikipedia,the last week of the ISO week-numbering year is the week before week 01; in accordance with the symmetry of the definition, equivalent definitions are:

* the week with the year’s last Thursday in it
* the week ending with the Sunday which is nearest in time to 31 December
* the week with December 28 in it
* the last week with the majority (four or more) of its days in the ending year
* the week starting with the Monday in the period 22 – 28 December
* the week with the Thursday in the period 25 – 31 December
* the week ending with the Sunday in the period 28 December – 3 January
* If 31 December is on a Monday, Tuesday, or Wednesday, it is in week 01 of the next year, otherwise in week 52 or 53.

So this plugin when calculating the weekno and if there is a WKST specification in the rule, uses “the week with December 28 in it” to calculate the last week and handle negative BYWEEKNO’s that way.

The logic is something like this

  • get the end of the year (ie 28th Dec)
  • determine the weekno (will be 52 or 53?)
  • go to the start of that week, using wkst
  • “save” the this and next 6 dates as our week

What do you think is the “first week” of the year ?

Week numbers and BYWEEKNO and weeks start with Monday, Sunday, Saturday (WKST)

How the week number is entered and sent in an ics file is important in two areas of this events plugin.

  1. For communication with other calendar systems, one must stick to the ical RFC5545 (ie : ISO 8601) definition so that recurring dates will be accurately reflected.
  2. For listing of events (agenda or calendar style) however there may be expectations of other week numberings (For example many timeshare resorts use very different week numbering systems, depending on when “their” weeks start – eg: Friday, Saturday, Sunday.)  It is simply not possible to cope with all of these, at this stage .  The RFC5545 spec (see below) implies that one can combine BYWEEKNO and WKST to give some flexibility.  The amr events plugin will pick up the week start defined in your wordpress website.
Entering the week number
Entering the week number for a recurring date in wordpress event plugin

What does the plugin do wrt week numbers ?

When entering a week number, the ISO8601 in combination with the weekstart (WKST ) will be expected.  To aid data entry, it will be checked against the start date (which must be in the week number) and the error message will tell you the wek number of the start date.

At launch, the listing plugin is limited to using the PHP functions for calculating the week number.

Week number definitions:

Wikipedia has some discussion on various usages or week number definitions under the 7 day week, week numbering heading.   There are many – it is not just a case of

  • which day the week starts on (Monday, Sunday, Saturday, Wednesday (Hungary?)), but also
  • what defines where one begins in the year with partial weeks or full weeks
    • Week containing Jan 1 (Eastern European, India, Arabic countries, Canada, China etc..)
    • Week containing Jan 4 (European countries)
    • Week containing Jan 7 & Monday  (Eastonia and Pakistan)

A list of these is available at pjh2.de and more information from JR Stockton

Technical Definitions of BYWEEKNO

From the RFC5545 Specification:

The BYWEEKNO rule part specifies a COMMA-separated list of ordinals specifying weeks of the year. Valid values are 1 to 53 or -53 to -1. This corresponds to weeks according to week numbering as defined in [ISO.8601.2004]. A week is defined as a seven day period, starting on the day of the week defined to be the week start (see WKST). Week number one of the calendar year is the first week that contains at least four (4) days in that calendar year. This rule part MUST NOT be used when the FREQ rule part is set to anything other than YEARLY. For example, 3 represents the third week of the year.
Note: Assuming a Monday week start, week 53 can only occur when Thursday is January 1 or if it is a leap year and Wednesday is January 1.

This note from aspose.com advises: Use BYWEEKNO only when conformance with ISO 8601 is required. Week numbers as defined by ISO 8601 are very different from week numbers in “common” sense.    According to ISO 8601, week number one of the calendar year is the first week of a calendar year that contains at least four days. This rule makes the algorithm specific to applications requiring conformance to ISO 8601 and make it almost inapplicable to other “normal” uses.

ISO 8601 is supported by some European banking and financial applications. It is also used in Television for booking commercials. An ISO week calculator can be found at http://www.personal.ecu.edu/mccartyr/isowdcal.html

The BYWEEKNO rule specifies a comma-delimited list of numbers identifying weeks of the year. Valid values are 1 to 53 and 1 to 53. This corresponds to weeks according to week numbering as defined in ISO 8601. BYWEEKNO is only valid for YEARLY rules.

To illustrate, the following are two very different recurrence patterns:

  • Friday of 1st ISO 8601 week of the year: FREQ=YEARLY;BYWEEKNO=1;BYDAY=FR
  • 1st Friday of the year : FREQ=YEARLY;BYDAY=1FR

In 1999, for example, 1st Friday of the year is 1999/01/01, while Friday of the 1st ISO 8601 week is 1999/01/08.

So what is the current week number?

These sites help if your week starts on a Monday:

Paydays, Last working days and why BYSETPOS is useful

Have you ever wondered how to represent important recurring events like a ‘payday’ or a last business day?

If your calendar application allows you to enter the “set position” along with other recurring rules, then you’ll need to know about BYSETPOS.

In a ical recurring event, the BYSETPOS is a comma separated list of numbers (1 to 366 or -1 to -366). It MUST be used with another ‘BY’ rule such as BYDAY, BYMONTH etc.

It “chooses” the ‘nth’ occurrence within a set of dates determined by the preceding rules.

For example, in a WEEKLY rule, the interval would be one week. (Remember to consider what the “start of the week” is for the set you are using). A set of recurrence instances starts at the beginning of the interval defined by the FREQ rule part.

Formal definition

For the formal definition see http://www.ietf.org/rfc/rfc5545.txt

Examples

The last work day of the month

FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1

‘PAY DAY’ – the last week day in the month!

RRULE:FREQ=MONTHLY;BYDAY=-1MO,-1TU,-1WE,-1TH,-1FR;BYSETPOS=-1

The 30th of every month; or the last day of the month if the 30th doesn’t exist

FREQ=MONTHLY;BYMONTHDAY=28,29,30;BYSETPOS=-1

For Developers

According to the very useful table of recurring rule precedence of page 43, the BYSETPOS is applied last within an iteration of the ‘FREQ’ on the set of dates generated by the rule.  If you programmaticaly follow the table logic, you should be able to avoid problems implementing BYSETPOS.