---
title: "Introduction to holideh"
output:
  rmarkdown::html_vignette:
    highlight: tango
    mathjax: null
    md_extensions: -smart
vignette: >
  %\VignetteIndexEntry{holideh}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

new_hooks <- fansi::set_knit_hooks(knitr::knit_hooks)

options(
  crayon.enabled = TRUE,
  rmarkdown.html_vignette.check_title = FALSE
)
```

This article contains some more in-depth examples on how the package can be used.

## Packages

```{r}
library(magrittr)
library(tibble)
library(dplyr)
library(lubridate)
library(purrr)
library(holideh)
```

## Get federal holidays

To get the federal holidays for the 2019 year, we can use:

```{r}
holidays19 <- get_holidays(2019, federal = TRUE)

holidays19
```

### More than one year

Since the `year` parameter of `get_holidays()` only accepts a single value, we can use
`purrr::map()` to get the holidays for multiple years, as a list. Since each list-element is a
tibble, we can follow this up with `purrr::list_rbind()` to combine all holidays into a single
tibble.

To get the federal holidays for the 2026 to 2028 years, we can use:

```{r}
holidays <- 2026:2028 %>%
  map(\(year) get_holidays(year, federal = TRUE)) %>%
  list_rbind()

holidays
```

The `observed_date` column is likely the column to be used in any calculations as this is the date
between Monday and Friday when the holiday is observed. For example, in the federal government, if
New Year's Day falls on a Sunday, then it is observed on the Monday (i.e. we don't work on the
Monday).

## Get holidays for a single province/territory

To get the holidays for the province of Ontario for the 2019 year, we can use:

```{r}
holidays_on19 <- get_province("ON", year = 2019)

holidays_on19
```

To get the holidays for more than one province/territory, or for a single province/territory over
multiple years, we can once again use `purrr::map()` for the iteration, and `purrr::list_rbind()`
to row-bind the results.

## Operations with business days

### A simple example

In 2027, Christmas and Boxing Day fall on Saturday and Sunday, respectively. Therefore, they will
be observed the proceeding Monday and Tuesday.

```{r}
simple_example <- tibble(
  dates = seq(from = ymd("2027-12-20"), to = ymd("2028-01-05"), by = "1 day")
)

simple_example
```

For a federal government setting, you will likely be using the observed dates, not the actual
holiday dates:

```{r}
holiday_dates <- pull(holidays, date)
obs_dates <- pull(holidays, observed_date)
```

The example below gives an overview of the helpers in this package:

```{r}
simple_example <- simple_example %>%
  mutate(
    # `wday()` is from lubridate
    day_of_week = wday(dates, label = TRUE, abbr = FALSE),
    
    # Check if a date is a weekend
    weekend = is_weekend(dates),
    
    # Check if a holiday falls on a date using the "actual dates"
    true_holiday = is_holiday(dates, holiday_dates),
    
    # Check if a holiday falls on a date using the "observed dates"
    obs_holiday = is_holiday(dates, obs_dates),
    
    # Check if a date is a business day (i.e. not holiday + not weekend)
    bizday = is_bizday(dates, holidays = obs_dates)
  ) %>%
  left_join(
    select(holidays, observed_date, name_en),
    by = c("dates" = "observed_date")
  )

simple_example
```

### A more difficult (realistic) example

Consider the scenario where we calculate productivity as the number of points accumulated in a
reporting period divided by the number of business days. In addition, suppose that the points are
reported on a biweekly basis on Wednesdays. Here, the goal is to make use of the `count_bizdays()`
function, which counts the number of business days between two dates (inclusively).

```{r, echo = FALSE}
set.seed(25)
```

```{r}
real_example <- tibble(
  end = seq(from = ymd("2027-11-03"), to = ymd("2028-01-27"), by = "2 weeks"),
  points = ceiling(runif(length(end), min = 90, max = 120))
)

real_example
```

To this data frame, we need to add the start of the reporting period (13 days prior):

```{r}
real_example <- real_example %>%
  mutate(start = end - days(13)) %>%
  relocate(start)

real_example
```

Now that we have the start and end dates, we can calculate the number of business days in the
reporting period. Note that `count_bizdays()` is not vectorised over `start` and `end`, so we will
need to wrap it in `map2_int()`. Once we have the number of business days, calculating productivity
is straightforward:

```{r}
real_example <- real_example %>%
  mutate(
    n_bizdays = map2_int(
      start, end,
      \(from, to) count_bizdays(from, to, holidays = obs_dates)
    ),
    productivity = points / n_bizdays
  )

real_example
```

We can check our work by zooming in to the period of 2027-12-16 to 2027-12-29 and making use of the
helper functions previously demonstrated in the simple example.

```{r}
tibble(
  dates = seq(from = ymd("2027-12-16"), to = ymd("2027-12-29"), by = "1 day"),
  day_of_week = wday(dates, label = TRUE, abbr = FALSE)
) %>%
  mutate(
    # Check if a date is a weekend
    weekend = is_weekend(dates),
    
    # Check if a holiday falls on a date using the "actual dates"
    true_holiday = is_holiday(dates, holiday_dates),
    
    # Check if a holiday falls on a date using the "observed dates"
    obs_holiday = is_holiday(dates, obs_dates),
    
    # Check if a date is a business day (i.e. not holiday + not weekend)
    bizday = is_bizday(dates, holidays = obs_dates)
  ) %>%
  left_join(
    select(holidays, observed_date, name_en),
    by = c("dates" = "observed_date")
  )
```

✅ There are eight business days in this reporting period, which matches our results above.
