Computing a US holiday calendar
Assume the existence of a
type date
and a function
nth_kday_of_month
with semantics described by
Boost.Datetime documentation. We also assume sums
type day_of_week=|Sunday|Monday|...
and
type ord=|First|second|...
.
These are utility functions I find myself writing time and time again.
let range l u =
let rec range_aux acc x y =
if x = y then acc
else range_aux (acc@[x]) (x+1) y
in
range_aux [] l u
let string_of_list f l = "[" ^ String.concat ";" (List.map f l) ^ "]"
The approach taken is to use date generators to convert abstract specification into a concrete set of dates.
let test () =
let us_holiday_calendar (s, e) =
let generators = [
nth_kday_of_month First Monday 09; (*US labor day*)
nth_kday_of_month Third Monday 01; (*Martin Luther King day*)
nth_kday_of_month Second Tuesday 02; (*President's day*)
nth_kday_of_month Fourth Thursday 11; (*Thanksgiving*)
] in
let years = range s e in
let apply_gen acc g = (acc@List.map g years) in
let holidays = List.fold_left apply_gen [] generators in
List.sort compare holidays in
assert_equal "[2014-01-20;2014-02-11;2014-09-01;2014-11-27;2015-01-19;2015-02-10;2015-09-07;2015-11-26;2016-01-18;2016-02-09;2016-09-05;2016-11-24;2017-01-16;2017-02-14;2017-09-04;2017-11-23;2018-01-15;2018-02-13;2018-09-03;2018-11-22;2019-01-21;2019-02-12;2019-09-02;2019-11-28;2020-01-20;2020-02-11;2020-09-07;2020-11-26;2021-01-18;2021-02-09;2021-09-06;2021-11-25;2022-01-17;2022-02-08;2022-09-05;2022-11-24;2023-01-16;2023-02-14;2023-09-04;2023-11-23]"
@@ (us_holiday_calendar (2014, 2024) |> string_of_list string_of_date)
This code calculates a 10y calendar of US holidays between 2014 and 2024. If the operators @@
and |>
are unfamiliar you can read about them here.