almanac provides low-level tools for building all manner of recurrence rules, but it also provides a fairly high-level set of tools for working with holidays and calendars. These are arguably the most useful part of almanac, because they do a lot of the heavy lifting of defining your own holidays and observance rules for you.
There are a number of pre-generated holidays in almanac, which all
hol_*(), such as
If the holiday is specific to a country, then it is also prefixed as
hol_us_veterans_day() (currently only global and
US holidays are provided).
A holiday object is just another type of recurrence schedule:
This means that you can use it with any of the
functions you might have learned about in the other vignettes.
You’ll use these holiday objects to build up a calendar, which is a bundle of individual holidays that represent the rules of your specific business.
There are 3 helpers that are specific to holidays:
hol_observe() adjusts a holiday to respect observance
rules that might be set by your company. For example, if Christmas falls
on Saturday, then your company may actually observe it on the
preceding Friday or following Monday.
on_christmas <- hol_christmas() %>% hol_observe(adjust_on = on_weekends, adjustment = adj_nearest) on_christmas #> <Christmas> #> <radjusted> #> adjust: #> <rrule> #> • frequency: yearly #> • range: [1900-01-01, 2100-01-01] #> • month of year: Dec #> • day of month: 25 #> adjust on: #> <rrule> #> • frequency: weekly #> • range: [1900-01-01, 2100-01-01] #> • day of week: Sat, and Sun
If you’ve read
vignette("adjust-and-shift"), then you’ll
recognize that observances look similar to
in fact that is the tooling that is used under the hood.
If we run our updated holiday through
again, you’ll see that it now rolls to the nearest weekday if Christmas
falls on a weekend.
hol_offset() allows you to create holidays that are
relative to some other holiday. For example, Good Friday is
always the Friday before Easter.
Let’s take a look at building a holiday for Boxing Day, the day after
hol_offset() retains the name of the original
holiday, so we’ll also need
hol_rename() to rename it to
Great! Now what if we wanted to add an observance rule to Boxing Day?
This is actually pretty complicated, because it is dependent on the
observance rules for Christmas. For example, if Christmas falls on a
Saturday, but is observed on Friday, then we probably want Boxing Day to
be observed on the following Monday. If Christmas falls on a Sunday and
is observed on the following Monday, then Boxing Day would be observed
on the following Tuesday. Luckily you can layer
hol_offset() to build up a
recurrence schedule that matches the rules we are looking for:
on_christmas <- hol_christmas() %>% hol_observe(adjust_on = on_weekends, adjustment = adj_nearest) on_boxing_day <- hol_christmas() %>% hol_observe(adjust_on = on_weekends, adjustment = adj_nearest) %>% hol_offset(by = 1) %>% hol_observe(adjust_on = on_weekends, adjustment = adj_following) %>% hol_rename("Boxing Day")
df <- data.frame( christmas = alma_events(on_christmas, year = 2020:2025), boxing_day = alma_events(on_boxing_day, year = 2020:2025) ) df$christmas_weekday <- lubridate::wday(df$christmas, label = TRUE) df$boxing_day_weekday <- lubridate::wday(df$boxing_day, label = TRUE) df #> christmas boxing_day christmas_weekday boxing_day_weekday #> 1 2020-12-25 2020-12-28 Fri Mon #> 2 2021-12-24 2021-12-27 Fri Mon #> 3 2022-12-26 2022-12-27 Mon Tue #> 4 2023-12-25 2023-12-26 Mon Tue #> 5 2024-12-25 2024-12-26 Wed Thu #> 6 2025-12-25 2025-12-26 Thu Fri
almanac doesn’t attempt to provide a comprehensive set of holidays.
Instead, it makes it easy for you to create your own using
rholiday(). All you need is a recurrence rule that aligns
with the holiday date and a name. Let’s create one for Canada Day, which
occurs on July 1st each year.
Holidays are great for one off operations, but typically if you are
building a business calendar then you’ll need to bundle multiple
holidays together. To do that, you’ll need a calendar object.
You can create one by providing holidays to
Like holidays, calendars are recurrence schedules that work with any
alma_*() functions, but they also have their own
If you’d like to generate the holidays for a particular year, then
you should use
This is similar to
alma_events(), but there are two big
The holiday name is displayed along with the event date
It has special support for observance rules
Note that we didn’t add any observance rules into our original calendar, let’s go back and adjust our holidays to roll off weekends:
cal <- rcalendar( hol_christmas() %>% hol_observe(adjust_on = on_weekends, adjustment = adj_nearest), hol_new_years_day() %>% hol_observe(adjust_on = on_weekends, adjustment = adj_nearest), # Canada normally rolls their holidays forward to the following Monday hol_canada_day() %>% hol_observe(adjust_on = on_weekends, adjustment = adj_following) )
Note that the holidays generated by
different from the previous ones because they now respect the observance
rules when a holiday falls on a weekend.
There is one more observance related feature worth pointing out. Let’s take a look at holidays for 2011:
New Year’s Day fell on a Saturday that year, so it was adjusted
backwards to the preceding Friday, which actually fell in 2010.
cal_events() is smart enough to know that if you are
requesting “2011’s holidays,” then New Year’s Day should probably be
included even if it was observed in a different year.
If you don’t want this behavior, you can set
observed = TRUE to use the observed year when filtering for
# New Year's Day is gone cal_events(cal, year = 2011, observed = TRUE) #> name date #> 1 Canada Day 2011-07-01 #> 2 Christmas 2011-12-26 # And is now listed twice here cal_events(cal, year = 2010, observed = TRUE) #> name date #> 1 New Year's Day 2010-01-01 #> 2 Canada Day 2010-07-01 #> 3 Christmas 2010-12-24 #> 4 New Year's Day 2010-12-31
If you’ve ever needed to determine if a date is a holiday, then
you’ve likely reached for
alma_in(), which works like
%in% and returns a logical vector. But if you also need to
determine which holiday that date corresponded to, then you’ll
need to use
Note that because our calendar has observance rules baked in, it
2010-12-31 (a Friday) as New Year’s Day rather than
the 1st of the year (a Saturday).
almanac comes with one pre-built calendar,
cal_us_federal(), which contains the federally recognized
holidays in the United States. It is meant to serve as an example of
what you can build with almanac, but it is also pretty useful on its
cal_events(cal_us_federal(), year = 2023) #> name date #> 1 New Year's Day 2023-01-02 #> 2 US Martin Luther King Jr. Day 2023-01-16 #> 3 US Presidents' Day 2023-02-20 #> 4 US Memorial Day 2023-05-29 #> 5 US Juneteenth 2023-06-19 #> 6 US Independence Day 2023-07-04 #> 7 US Labor Day 2023-09-04 #> 8 US Indigenous Peoples' Day 2023-10-09 #> 9 US Veterans Day 2023-11-10 #> 10 US Thanksgiving 2023-11-23 #> 11 Christmas 2023-12-25
Note that this calendar doesn’t claim to be historically accurate, it is only intended to be a representation of the current federally recognized holidays. You can build historically accurate calendars (i.e. you can represent that Juneteenth wasn’t celebrated before 2021) it just takes a bit more effort.