257 lines
11 KiB
Python
257 lines
11 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
# python-holidays
|
||
|
# ---------------
|
||
|
# A fast, efficient Python library for generating country, province and state
|
||
|
# specific sets of holidays on the fly. It aims to make determining whether a
|
||
|
# specific date is a holiday as fast and flexible as possible.
|
||
|
#
|
||
|
# Author: ryanss <ryanssdev@icloud.com> (c) 2014-2017
|
||
|
# dr-prodigy <maurizio.montel@gmail.com> (c) 2017-2020
|
||
|
# Website: https://github.com/dr-prodigy/python-holidays
|
||
|
# License: MIT (see LICENSE file)
|
||
|
|
||
|
from datetime import date
|
||
|
|
||
|
from dateutil.easter import easter
|
||
|
from dateutil.relativedelta import relativedelta as rd, MO, SU, FR
|
||
|
|
||
|
from holidays.constants import FRI, SAT, SUN, WEEKEND
|
||
|
from holidays.constants import JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, \
|
||
|
OCT, \
|
||
|
NOV, DEC
|
||
|
from holidays.holiday_base import HolidayBase
|
||
|
|
||
|
|
||
|
class Canada(HolidayBase):
|
||
|
PROVINCES = ['AB', 'BC', 'MB', 'NB', 'NL', 'NS', 'NT', 'NU', 'ON', 'PE',
|
||
|
'QC', 'SK', 'YT']
|
||
|
|
||
|
def __init__(self, **kwargs):
|
||
|
self.country = 'CA'
|
||
|
self.prov = kwargs.pop('prov', 'ON')
|
||
|
HolidayBase.__init__(self, **kwargs)
|
||
|
|
||
|
def _populate(self, year):
|
||
|
# New Year's Day
|
||
|
if year >= 1867:
|
||
|
name = "New Year's Day"
|
||
|
self[date(year, JAN, 1)] = name
|
||
|
if self.observed and date(year, JAN, 1).weekday() == SUN:
|
||
|
self[date(year, JAN, 1) + rd(days=+1)] = name + \
|
||
|
" (Observed)"
|
||
|
elif self.observed \
|
||
|
and date(year, JAN, 1).weekday() == SAT:
|
||
|
# Add Dec 31st from the previous year without triggering
|
||
|
# the entire year to be added
|
||
|
expand = self.expand
|
||
|
self.expand = False
|
||
|
self[date(year, JAN, 1) + rd(days=-1)] = name + \
|
||
|
" (Observed)"
|
||
|
self.expand = expand
|
||
|
# The next year's observed New Year's Day can be in this year
|
||
|
# when it falls on a Friday (Jan 1st is a Saturday)
|
||
|
if self.observed and date(year, DEC, 31).weekday() == FRI:
|
||
|
self[date(year, DEC, 31)] = name + " (Observed)"
|
||
|
|
||
|
# Family Day / Louis Riel Day (MB) / Islander Day (PE)
|
||
|
# / Heritage Day (NS, YT)
|
||
|
if self.prov in ('AB', 'SK', 'ON') and year >= 2008:
|
||
|
self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Family Day"
|
||
|
elif self.prov in ('AB', 'SK') and year >= 2007:
|
||
|
self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Family Day"
|
||
|
elif self.prov == 'AB' and year >= 1990:
|
||
|
self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Family Day"
|
||
|
elif self.prov == 'NB' and year >= 2018:
|
||
|
self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Family Day"
|
||
|
elif self.prov == 'BC':
|
||
|
if year >= 2013 and year <= 2018:
|
||
|
self[date(year, FEB, 1) + rd(weekday=MO(+2))] = \
|
||
|
"Family Day"
|
||
|
elif year > 2018:
|
||
|
self[date(year, FEB, 1) + rd(weekday=MO(+3))] = \
|
||
|
"Family Day"
|
||
|
elif self.prov == 'MB' and year >= 2008:
|
||
|
self[date(year, FEB, 1) + rd(weekday=MO(+3))] = \
|
||
|
"Louis Riel Day"
|
||
|
elif self.prov == 'PE' and year >= 2010:
|
||
|
self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Islander Day"
|
||
|
elif self.prov == 'PE' and year == 2009:
|
||
|
self[date(year, FEB, 1) + rd(weekday=MO(+2))] = "Islander Day"
|
||
|
elif self.prov == 'NS' and year >= 2015:
|
||
|
# http://novascotia.ca/lae/employmentrights/NovaScotiaHeritageDay.asp
|
||
|
self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Heritage Day"
|
||
|
elif self.prov == 'YT':
|
||
|
# start date?
|
||
|
# http://heritageyukon.ca/programs/heritage-day
|
||
|
# https://en.wikipedia.org/wiki/Family_Day_(Canada)#Yukon_Heritage_Day
|
||
|
# Friday before the last Sunday in February
|
||
|
dt = date(year, MAR, 1) + rd(weekday=SU(-1)) + rd(weekday=FR(-1))
|
||
|
self[dt] = "Heritage Day"
|
||
|
|
||
|
# St. Patrick's Day
|
||
|
if self.prov == 'NL' and year >= 1900:
|
||
|
dt = date(year, MAR, 17)
|
||
|
# Nearest Monday to March 17
|
||
|
dt1 = date(year, MAR, 17) + rd(weekday=MO(-1))
|
||
|
dt2 = date(year, MAR, 17) + rd(weekday=MO(+1))
|
||
|
if dt2 - dt <= dt - dt1:
|
||
|
self[dt2] = "St. Patrick's Day"
|
||
|
else:
|
||
|
self[dt1] = "St. Patrick's Day"
|
||
|
|
||
|
# Good Friday
|
||
|
if self.prov != 'QC' and year >= 1867:
|
||
|
self[easter(year) + rd(weekday=FR(-1))] = "Good Friday"
|
||
|
|
||
|
# Easter Monday
|
||
|
if self.prov == 'QC' and year >= 1867:
|
||
|
self[easter(year) + rd(weekday=MO)] = "Easter Monday"
|
||
|
|
||
|
# St. George's Day
|
||
|
if self.prov == 'NL' and year == 2010:
|
||
|
# 4/26 is the Monday closer to 4/23 in 2010
|
||
|
# but the holiday was observed on 4/19? Crazy Newfies!
|
||
|
self[date(2010, 4, 19)] = "St. George's Day"
|
||
|
elif self.prov == 'NL' and year >= 1990:
|
||
|
dt = date(year, APR, 23)
|
||
|
# Nearest Monday to April 23
|
||
|
dt1 = dt + rd(weekday=MO(-1))
|
||
|
dt2 = dt + rd(weekday=MO(+1))
|
||
|
if dt2 - dt < dt - dt1:
|
||
|
self[dt2] = "St. George's Day"
|
||
|
else:
|
||
|
self[dt1] = "St. George's Day"
|
||
|
|
||
|
# Victoria Day / National Patriots' Day (QC)
|
||
|
if self.prov not in ('NB', 'NS', 'PE', 'NL', 'QC') and year >= 1953:
|
||
|
self[date(year, MAY, 24) + rd(weekday=MO(-1))] = "Victoria Day"
|
||
|
elif self.prov == 'QC' and year >= 1953:
|
||
|
name = "National Patriots' Day"
|
||
|
self[date(year, MAY, 24) + rd(weekday=MO(-1))] = name
|
||
|
|
||
|
# National Aboriginal Day
|
||
|
if self.prov == 'NT' and year >= 1996:
|
||
|
self[date(year, JUN, 21)] = "National Aboriginal Day"
|
||
|
|
||
|
# St. Jean Baptiste Day
|
||
|
if self.prov == 'QC' and year >= 1925:
|
||
|
self[date(year, JUN, 24)] = "St. Jean Baptiste Day"
|
||
|
if self.observed and date(year, JUN, 24).weekday() == SUN:
|
||
|
self[date(year, JUN, 25)] = "St. Jean Baptiste Day (Observed)"
|
||
|
|
||
|
# Discovery Day
|
||
|
if self.prov == 'NL' and year >= 1997:
|
||
|
dt = date(year, JUN, 24)
|
||
|
# Nearest Monday to June 24
|
||
|
dt1 = dt + rd(weekday=MO(-1))
|
||
|
dt2 = dt + rd(weekday=MO(+1))
|
||
|
if dt2 - dt <= dt - dt1:
|
||
|
self[dt2] = "Discovery Day"
|
||
|
else:
|
||
|
self[dt1] = "Discovery Day"
|
||
|
elif self.prov == 'YT' and year >= 1912:
|
||
|
self[date(year, AUG, 1) + rd(weekday=MO(+3))] = "Discovery Day"
|
||
|
|
||
|
# Canada Day / Memorial Day (NL)
|
||
|
if self.prov != 'NL' and year >= 1867:
|
||
|
if year >= 1983:
|
||
|
name = "Canada Day"
|
||
|
else:
|
||
|
name = "Dominion Day"
|
||
|
self[date(year, JUL, 1)] = name
|
||
|
if year >= 1879 and self.observed \
|
||
|
and date(year, JUL, 1).weekday() in WEEKEND:
|
||
|
self[date(year, JUL, 1) + rd(weekday=MO)] = name + \
|
||
|
" (Observed)"
|
||
|
elif year >= 1867:
|
||
|
if year >= 1983:
|
||
|
name = "Memorial Day"
|
||
|
else:
|
||
|
name = "Dominion Day"
|
||
|
self[date(year, JUL, 1)] = name
|
||
|
if year >= 1879 and self.observed \
|
||
|
and date(year, JUL, 1).weekday() in WEEKEND:
|
||
|
self[date(year, JUL, 1) + rd(weekday=MO)] = name + \
|
||
|
" (Observed)"
|
||
|
|
||
|
# Nunavut Day
|
||
|
if self.prov == 'NU' and year >= 2001:
|
||
|
self[date(year, JUL, 9)] = "Nunavut Day"
|
||
|
if self.observed and date(year, JUL, 9).weekday() == SUN:
|
||
|
self[date(year, JUL, 10)] = "Nunavut Day (Observed)"
|
||
|
elif self.prov == 'NU' and year == 2000:
|
||
|
self[date(2000, 4, 1)] = "Nunavut Day"
|
||
|
|
||
|
# Civic Holiday
|
||
|
if self.prov in ('ON', 'MB', 'NT') and year >= 1900:
|
||
|
self[date(year, AUG, 1) + rd(weekday=MO)] = "Civic Holiday"
|
||
|
elif self.prov == 'AB' and year >= 1974:
|
||
|
# https://en.wikipedia.org/wiki/Civic_Holiday#Alberta
|
||
|
self[date(year, AUG, 1) + rd(weekday=MO)] = "Heritage Day"
|
||
|
elif self.prov == 'BC' and year >= 1974:
|
||
|
# https://en.wikipedia.org/wiki/Civic_Holiday
|
||
|
self[date(year, AUG, 1) + rd(weekday=MO)] = \
|
||
|
"British Columbia Day"
|
||
|
elif self.prov == 'NB' and year >= 1900:
|
||
|
# https://en.wikipedia.org/wiki/Civic_Holiday
|
||
|
self[date(year, AUG, 1) + rd(weekday=MO)] = "New Brunswick Day"
|
||
|
elif self.prov == 'SK' and year >= 1900:
|
||
|
# https://en.wikipedia.org/wiki/Civic_Holiday
|
||
|
self[date(year, AUG, 1) + rd(weekday=MO)] = "Saskatchewan Day"
|
||
|
|
||
|
# Labour Day
|
||
|
if year >= 1894:
|
||
|
self[date(year, SEP, 1) + rd(weekday=MO)] = "Labour Day"
|
||
|
|
||
|
# Thanksgiving
|
||
|
if self.prov not in ('NB', 'NS', 'PE', 'NL') and year >= 1931:
|
||
|
if year == 1935:
|
||
|
# in 1935, Canadian Thanksgiving was moved due to the General
|
||
|
# Election falling on the second Monday of October
|
||
|
# https://books.google.ca/books?id=KcwlQsmheG4C&pg=RA1-PA1940&lpg=RA1-PA1940&dq=canada+thanksgiving+1935&source=bl&ots=j4qYrcfGuY&sig=gxXeAQfXVsOF9fOwjSMswPHJPpM&hl=en&sa=X&ved=0ahUKEwjO0f3J2PjOAhVS4mMKHRzKBLAQ6AEIRDAG#v=onepage&q=canada%20thanksgiving%201935&f=false
|
||
|
self[date(1935, 10, 25)] = "Thanksgiving"
|
||
|
else:
|
||
|
self[date(year, OCT, 1) + rd(weekday=MO(+2))] = \
|
||
|
"Thanksgiving"
|
||
|
|
||
|
# Remembrance Day
|
||
|
name = "Remembrance Day"
|
||
|
provinces = ('ON', 'QC', 'NS', 'NL', 'NT', 'PE', 'SK')
|
||
|
if self.prov not in provinces and year >= 1931:
|
||
|
self[date(year, NOV, 11)] = name
|
||
|
elif self.prov in ('NS', 'NL', 'NT', 'PE', 'SK') and year >= 1931:
|
||
|
self[date(year, NOV, 11)] = name
|
||
|
if self.observed and date(year, NOV, 11).weekday() == SUN:
|
||
|
name = name + " (Observed)"
|
||
|
self[date(year, NOV, 11) + rd(weekday=MO)] = name
|
||
|
|
||
|
# Christmas Day
|
||
|
if year >= 1867:
|
||
|
self[date(year, DEC, 25)] = "Christmas Day"
|
||
|
if self.observed \
|
||
|
and date(year, DEC, 25).weekday() == SAT:
|
||
|
self[date(year, DEC, 24)] = "Christmas Day (Observed)"
|
||
|
elif self.observed \
|
||
|
and date(year, DEC, 25).weekday() == SUN:
|
||
|
self[date(year, DEC, 26)] = "Christmas Day (Observed)"
|
||
|
|
||
|
# Boxing Day
|
||
|
if year >= 1867:
|
||
|
name = "Boxing Day"
|
||
|
name_observed = name + " (Observed)"
|
||
|
if self.observed and date(year, DEC, 26).weekday() in WEEKEND:
|
||
|
self[date(year, DEC, 26) + rd(weekday=MO)] = name_observed
|
||
|
elif self.observed and date(year, DEC, 26).weekday() == 0:
|
||
|
self[date(year, DEC, 27)] = name_observed
|
||
|
else:
|
||
|
self[date(year, DEC, 26)] = name
|
||
|
|
||
|
|
||
|
class CA(Canada):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class CAN(Canada):
|
||
|
pass
|