3

I am trying to parse an RRULE and display what weeks in the month a recurrence event is valid for. I have looked at the RFC2445 doc (http://www.ietf.org/rfc/rfc2445.txt) and it's not that clear.

I know for instance the rule:

RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,FR,WE;BYSETPOS=10,11,12,7,8,9,1,2,3,4,5,6

Is for Wed, Thur, Friday on the 1st,2nd,3rd and 4th week of the month.

or

RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,MO;BYSETPOS=3,4,5,6;

Is for Monday and Tuesday on the 2nd and 3rd week of the month.

or

RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,WE;BYSETPOS=-1,-2

Is for Wed and Thursday on the last week of the month.

I generated these via another program, but am not sure how it actually generated them.

Thus the problem I am having is understanding how the BYSETPOS describes reoccurrence weeks for a month. The final goal is to be able to parse a RRULE such as the above and display at like so:

For: RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,FR,WE;BYSETPOS=10,11,12,7,8,9,1,2,3,4,5,6

Show: Thur,Friday,Wed on week:1,2,3,4

For: RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,MO;BYSETPOS=3,4,5,6;

Show: Tues, Monday on week:2,3

For: RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,WE;BYSETPOS=-1,-2

Show: Whu,Wed on last week

The best solution would be a string in objective-c, but I can figure it out if it's another C like language. Even just a explanation of how BYSETPOS with BYDAY works would be great.

rink.attendant.6
  • 44,500
  • 61
  • 101
  • 156

2 Answers2

9

Thus the problem I am having is understanding how the BYSETPOS describes reoccurrence weeks for a month.

BYSETPOS does not represent weeks but simply the nth instance once you have calculated the instances corresponding to the remaining of the rule. For example, FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,MO corresponds to every mondays and tuesdays of the month, every month. So for each month, you first calculate a set (e.g. 9 entries if you take July 2014). Then BYSETPOS gives you the "indexes" into the set that you should keep, -1,-2 meaning the last 2 entries into the set.

Continuing with the July 2014 example, the base rule will return the following set: (1st, 7th, 8th, 14th, 15th, 21st, 22nd, 28th, 29th of July). Given a BYSETPOS=1,2,-1,-2, we will keep 1st, 7th, 28th, 29th of July.

You want to look at https://www.rfc-editor.org/rfc/rfc5545 which obsoletes RFC2245 and has a more detailed description of recurrence rules.

Community
  • 1
  • 1
Arnaud Quillaud
  • 4,420
  • 1
  • 12
  • 8
  • Sorry, I guess I am still a bit confused. So for July 2014 the set for TU, Mo will be: 1,2,2,3,3,4,4,5,5 RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,MO;BYSETPOS=1,2,-1,-2 So -1 & -2 will grab 5,5 stating that TU and MO are for 5th week for that month. But where I am still not seeing it is in say: RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,MO;BYSETPOS=1,2,-1,-2 Which I have set for 1st and last week of the month, which gives me 1,2 and 5,5 for the weeks. – Doron Kramarczyk Jul 25 '14 at 14:39
  • Did edit my response with the BYSETPOS=1,2,-1,-2 example for July 2014 – Arnaud Quillaud Aug 07 '14 at 12:53
  • 2
    Can I just clarify whether `BYDAY=MO;BYSETPOS=-1` is the same as `BYDAY=-1MO`? – u01jmg3 Apr 11 '15 at 19:47
  • @u01jmg3 Yes they're exactly the same. – Nicolas Oct 16 '19 at 22:36
0

Good explanation Arnaud. Helped me get my own head around it.

Because this is such an unusual concept for myself and others to grasp, I have copied a wiki page I created for myself along with a short php script I've created to clearly understand by demonstration how it works.

BYSETPOS is not a rule but something that limits an existing rrule.

For instance, let's say you have an RRULE for an event that occurs twice a month on Mon and Tue forever like this:

FREQ=MONTHLY;INTERVAL=1;BYDAY=MO,TU

Now let take the example Arnaud provided above and focus only on the month of July as an example.

July 1st is the first Wed July 7th is the following Tue followed by the 8th being the next Wed and so on. Our RRULE above would have the event falling on July 1st, 7th, 8th, 14th, 15th, 21st, 22nd, 28th and 29th Now let us append a BYSETPOS limiter.

FREQ=MONTHLY;INTERVAL=1;BYDAY=MO,TU;BYSETPOS=1,2,-1,-2

What is this saying exactly?

It is saying OK, we know your rule would have the event falling on July 1st, 7th, 8th, 14th, 15th, 21st, 22nd, 28th and 29th. However, we only want display the 1st, 2nd instances (1,2) of the event as well as the last (-1) and the 2nd to the last (-2).

BYSETPOS says to show ONLY those instances that are in the BYSETPOS limiter.

So if you took the array of days $moDays Array(1,7,8,14,15,21,22,28,29) and parsed it with the BYSETPOS limiter $bspLimiter=Array(1,2,-1,-2) it would look likethe following:

<?php
// 9 event days - limiting the events displayed based on the BYSETPOS limiter

$moDays = array(1,7,8,14,15,21,22,28,29);
$bspLimiter = array(1,2,-1,-2);
$keepers = [];
for($b=0;$b<count($bspLimiter);$b++){
    if($bspLimiter[$b] < 0){
        echo '$bspLimiter[$b] is negative value ('.$bspLimiter[$b].') so getting from back of array<br>';
        $limiter=count($moDays)+$bspLimiter[$b];
        $keeper=$moDays[$limiter];
        $keepers[]=$keeper;
    } else {
        # accounting for index
        $limiter = $bspLimiter[$b]-1;
        $keeper=$moDays[$limiter];
        $keepers[]=$keeper;
    }

    echo '<b>keeping '.$keeper."</b><Br>";

}
echo "<hr>";
asort($keepers);
echo $keepers=str_replace("'","",implode("', '", $keepers));
?>
Jay Lepore
  • 85
  • 1
  • 7