---
title: "iCalendar specification"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{iCalendar specification}
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}
editor_options: 
  chunk_output_type: console
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

The Internet Engineering Task Force (IETF) has released an _exhaustive_ guide about how to design a calendar application. It is known as the [iCalendar specification guide, RFC-5545](https://www.rfc-editor.org/rfc/rfc5545). Recurrence rules are a small subsection of this, and the JavaScript library underlying almanac was built to comply with the specification guide. To show that almanac also complies with (pretty much all) of the guide as well, this vignette will go through the large list of examples that the guide provides to ensure that your application is doing the right thing. This will also serve as a way to show how flexible almanac is to construct a wide range of recurrence rules.

The specific section of the iCalendar guide that mentions recurrence rules is [3.3.10](https://www.rfc-editor.org/rfc/rfc5545#section-3.3.10), and the section with all of the examples is [3.8.5.3](https://www.rfc-editor.org/rfc/rfc5545#section-3.8.5.3).

For whatever reason, most examples use a start date of `1997-09-02`. To show the results, for terminating recurrence rules (those that have a limited count or an until date) I will use `alma_search()` with `since` as the `from` date and a `to` date far enough in the future to show useful results. For non-terminating rules, I will choose a `to` date that shows enough to be informative, without being overwhelming.

```{r setup}
library(almanac)

since <- as.Date("1997-09-02")
to <- as.Date("2010-01-01")
```

### Daily for 10 events

```{r}
rrule <- daily(since) %>%
  recur_for_count(10)

alma_search(since, to, rrule)
```

### Daily until 1997-12-24

```{r}
rrule <- daily(since, until = "1997-12-24")

alma_search(since, to, rrule)
```

### Every other day, forever

```{r}
rrule <- daily(since) %>%
  recur_on_interval(2)

alma_search(since, "1997-10-01", rrule)
```

### Every 10 days, 5 events

```{r}
rrule <- daily(since) %>%
  recur_on_interval(10) %>%
  recur_for_count(5)

alma_search(since, to, rrule)
```

### Every day in January, for 3 years

```{r}
rrule <- daily(since = "1998-01-01", until = "2000-01-31") %>%
  recur_on_month_of_year("January")

alma_search(since, to, rrule)
```

### Weekly for 10 events

```{r}
rrule <- weekly(since) %>%
  recur_for_count(10)

alma_search(since, to, rrule)
```

### Weekly until December 24, 1997

```{r}
rrule <- weekly(since, until = "1997-12-24")

alma_search(since, to, rrule)
```

### Every other week - forever

```{r}
rrule <- weekly(since) %>%
  recur_on_interval(2)

alma_search(since, "1997-11-01", rrule)
```

### Weekly on Tuesday and Thursday for five weeks

```{r}
rrule <- weekly(since) %>%
  recur_on_day_of_week(c("Tue", "Thur")) %>%
  recur_for_count(10)

alma_search(since, to, rrule)
```

### Every other week on Monday, Wednesday, and Friday until December 24, 1997, starting on Monday, September 1, 1997

```{r}
rrule <- weekly(since = "1997-09-01", until = "1997-12-24") %>%
  recur_on_day_of_week(c("Mon", "Wed", "Fri")) %>%
  recur_on_interval(2)

alma_search("1997-09-01", to, rrule)
```

### Every other week on Tuesday and Thursday, for 8 events

```{r}
rrule <- weekly(since) %>%
  recur_on_day_of_week(c("Tue", "Thu")) %>%
  recur_on_interval(2) %>%
  recur_for_count(8)

alma_search(since, to, rrule)
```

### Monthly on the first Friday for 10 events

```{r}
rrule <- monthly("1997-09-05") %>%
  recur_on_day_of_week("Fri", nth = 1) %>%
  recur_for_count(10)

alma_search(since, to, rrule)
```

### Monthly on the first Friday until December 24, 1997

```{r}
rrule <- monthly(since = "1997-09-05", until = "1997-12-24") %>%
  recur_on_day_of_week("Fri", nth = 1)

alma_search(since, to, rrule)
```

### Every other month on the first and last Sunday of the month for 10 events

```{r}
rrule <- monthly("1997-09-07") %>%
  recur_on_day_of_week("Sun", nth = c(1, -1)) %>%
  recur_on_interval(2) %>%
  recur_for_count(10)

alma_search(since, to, rrule)
```

### Monthly on the second-to-last Monday of the month for 6 months

```{r}
rrule <- monthly("1997-09-22") %>%
  recur_on_day_of_week("Mon", nth = -2) %>%
  recur_for_count(6)

alma_search(since, to, rrule)
```

### Monthly on the third-to-the-last day of the month, forever

```{r}
rrule <- monthly("1997-09-28") %>%
  recur_on_day_of_month(-3)

alma_search(since, "1997-12-01", rrule)
```

### Monthly on the 2nd and 15th of the month for 10 events

```{r}
rrule <- monthly("1997-09-02") %>%
  recur_on_day_of_month(c(2, 15)) %>%
  recur_for_count(10)

alma_search(since, to, rrule)
```

### Monthly on the first and last day of the month for 10 events

```{r}
rrule <- monthly("1997-09-30") %>%
  recur_on_day_of_month(c(1, -1)) %>%
  recur_for_count(10)

alma_search(since, to, rrule)
```

### Every 18 months on the 10th thru 15th of the month for 10 events

```{r}
rrule <- monthly("1997-09-10") %>%
  recur_on_interval(18) %>%
  recur_on_day_of_month(10:15) %>%
  recur_for_count(10)

alma_search("1997-09-10", to, rrule)
```

### Every Tuesday, every other month

```{r}
rrule <- monthly(since) %>%
  recur_on_interval(2) %>%
  recur_on_day_of_week("Tuesday")

alma_search(since, "1997-12-01", rrule)
```

### Yearly in June and July for 10 events

Note that the day of the month is taken from the `since` date, since it is not otherwise specified!

```{r}
rrule <- yearly("1997-06-10") %>%
  recur_on_month_of_year(c("June", "July")) %>%
  recur_for_count(10)

alma_search("1997-06-10", to, rrule)
```

### Every other year on January, February, and March for 10 events

```{r}
rrule <- yearly("1997-03-10") %>%
  recur_on_month_of_year(c("Jan", "Feb", "Mar")) %>%
  recur_on_interval(2) %>%
  recur_for_count(10)

alma_search("1997-03-10", to, rrule)
```

### Every third year on the 1st, 100th, and 200th day for 10 events

```{r}
rrule <- yearly("1997-01-01") %>%
  recur_on_day_of_year(c(1, 100, 200)) %>%
  recur_on_interval(3) %>%
  recur_for_count(10)

alma_search("1997-01-01", to, rrule)
```

### Every 20th Monday of the year, forever

```{r}
rrule <- yearly("1997-05-19") %>%
  recur_on_day_of_week("Monday", nth = 20)

alma_search("1997-05-19", "2000-01-01", rrule)
```

### Monday of week number 20 (where the default start of the week is Monday), forever

Default week start in almanac is on Monday.

```{r}
rrule <- yearly("1997-05-12") %>%
  recur_on_week_of_year(20) %>%
  recur_on_day_of_week("Monday")

alma_search("1997-05-12", "2000-01-01", rrule)
```

### Every Thursday in March, forever

```{r}
rrule <- yearly("1997-03-13") %>%
  recur_on_day_of_week("Thursday") %>%
  recur_on_month_of_year("March")

alma_search("1997-03-13", "2000-01-01", rrule)
```

### Every Thursday, but only during June, July, and August, forever

```{r}
rrule <- yearly("1997-06-05") %>%
  recur_on_day_of_week("Thursday") %>%
  recur_on_month_of_year(c("Jun", "July", "Aug"))

alma_search("1997-06-05", "1999-01-01", rrule)
```

### Every Friday the 13th, forever

```{r}
rrule <- yearly(since) %>%
  recur_on_day_of_week("Friday") %>%
  recur_on_day_of_month(13)

alma_search(since, "2001-01-01", rrule)
```

### The first Saturday that follows the first Sunday of the month, forever

```{r}
rrule <- yearly("1997-09-13") %>%
  recur_on_day_of_week("Saturday") %>%
  recur_on_day_of_month(7:13)

alma_search("1997-09-13", "1998-06-01", rrule)
```

### Every 4 years, the first Tuesday after a Monday in November, forever (U.S. Presidential Election day)

```{r}
rrule <- yearly("1996-11-05") %>%
  recur_on_day_of_week("Tuesday") %>%
  recur_on_day_of_month(2:8) %>%
  recur_on_interval(4) %>%
  recur_on_month_of_year("November")

alma_search("1996-11-05", "2010-12-31", rrule)
```

### The third instance into the month of one of Tuesday, Wednesday, or Thursday, for the next 3 months

`recur_on_position()` is an incredibly powerful tool, allowing you to select a position _within the frequency_. So this selects the third element of each monthly set, where the monthly set contains all of the Tuesday, Wednesday, and Thursdays of the month.

```{r}
rrule <- monthly("1997-09-04") %>%
  recur_on_day_of_week(c("Tue", "Wed", "Thu")) %>%
  recur_on_position(3) %>%
  recur_for_count(3)

alma_search("1997-09-04", to, rrule)
```

### The second-to-last weekday of the month

```{r}
rrule <- monthly("1997-09-29") %>%
  recur_on_day_of_week(1:5) %>%
  recur_on_position(-2)

alma_search("1997-09-29", "1998-12-01", rrule)
```

### An example where the days generated makes a difference because of week_start

```{r}
rrule <- weekly("1997-08-05") %>%
  recur_on_interval(2) %>%
  recur_for_count(4) %>%
  recur_on_day_of_week(c("Tue", "Sun")) %>%
  recur_with_week_start("Monday")

# Week 1: 1997-08-04 -> 1997-08-10
# Week 2: 1997-08-11 -> 1997-08-17 (skipped)
# Week 3: 1997-08-18 -> 1997-08-24 
alma_search("1997-08-05", "1998-12-01", rrule)
```

Changing the week start to Sunday.

```{r}
rrule <- weekly("1997-08-05") %>%
  recur_on_interval(2) %>%
  recur_for_count(4) %>%
  recur_on_day_of_week(c("Tue", "Sun")) %>%
  recur_with_week_start("Sunday")

# Week 1: 1997-08-03 -> 1997-08-09
# Week 2: 1997-08-10 -> 1997-08-16 (skipped)
# Week 3: 1997-08-17 -> 1997-08-23
# Week 4: 1997-08-24 -> 1997-08-30 (skipped)
# Week 5: 1997-08-31 -> 1997-09-06
alma_search("1997-08-05", "1998-12-01", rrule)
```

### An example where an invalid date (i.e., February 30) is ignored

Invalid dates do not decrease the total count.

```{r}
rrule <- weekly("2007-01-15") %>%
  recur_on_day_of_month(c(15, 30)) %>%
  recur_for_count(5)

alma_search("2007-01-15", "2007-12-31", rrule)
```
