module Data.Time.Calendar.BankHoliday.UnitedStates
(
isBankHoliday
, bankHolidays
, holidaysBetween
, holidaysBetweenYears
) where
import Data.Maybe
import Data.Time (Day, fromGregorian, toGregorian)
import Data.Time.Calendar (addDays, toModifiedJulianDay)
import Data.Time.Calendar.BankHoliday (isWeekday, isWeekend, yearFromDay)
bankHolidays :: Integer -> [Day]
bankHolidays year = filterHistoric standardHolidays
where
[jan, feb, jun, jul, sep, oct, nov, dec] = monthsMap
monthsMap = map (fromGregorian year) [1,2,6,7,9,10,11,12]
standardHolidays = [
2 `weeksAfter` firstMondayIn jan
, 2 `weeksAfter` firstMondayIn feb
, weekBefore (firstMondayIn jun)
, firstMondayIn sep
, weekAfter (firstMondayIn oct)
, 2 `weeksAfter` firstThursdayIn nov
] ++ catMaybes [
weekendHolidayFrom (jan 1)
, weekendHolidayFrom (jul 4)
, weekendHolidayFrom (nov 11)
, weekendHolidayFrom (dec 25)
]
isBankHoliday :: Day -> Bool
isBankHoliday d = d `elem` bankHolidays (yearFromDay d)
filterHistoric :: [Day] -> [Day]
filterHistoric = filter (\d -> d > marchNinth1933)
where marchNinth1933 = fromGregorian 1933 3 9
holidaysBetweenYears :: Integer -> Integer -> [Day]
holidaysBetweenYears startYear endYear =
foldl (++) [] (map bankHolidays [startYear..endYear])
holidaysBetween :: Day -> Day -> [Day]
holidaysBetween start end =
filter (\a -> a >= start && a <= end) fullRange
where
fullRange = holidaysBetweenYears (yearFromDay start) (yearFromDay end)
weekendHolidayFrom :: Day -> Maybe Day
weekendHolidayFrom d = case weekIndex d of
3 -> Nothing
4 -> Just (addDays 1 d)
_ -> Just d
weekIndex day = toModifiedJulianDay day `mod` 7
firstMondayIn month = addDays (negate $ weekIndex (month 02)) (month 07)
firstThursdayIn month = addDays 3 (firstMondayIn month)
weeksBefore n = addDays (n * (7))
weekBefore = weeksBefore 1
weeksAfter n = addDays (n * 7)
weekAfter = weeksAfter 1