diff --git a/.travis.yml b/.travis.yml index 470a96c27..213816284 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ install: matrix: include: -# - python: '3.9' + - python: '3.9' - python: '3.8' - python: '3.7' - python: '3.6' diff --git a/CHANGES b/CHANGES index e1bd7d2f0..88661b333 100644 --- a/CHANGES +++ b/CHANGES @@ -5,11 +5,22 @@ Released ????? ??, ???? - Support for Djibouti (Abdisamade) - Support for United Arab Emirates (marcomasulli, mborsetti) +- Support for Chile (mborsetti, dr-p) +- Support for Angola (pietervdw115) - Korea 2020 fix (MYUNGJE, dr-p) - Australia 2020 fix (bencollerson, trauty-is-me) -- Croatia fixes (jangrg, dr-p) -- United States fixes (raffg, dr-p) +- Croatia fixes and updates (jangrg, mborsetti, dr-p) +- United States fixes (raffg, bgmiles, dr-p) - UK fixes (dr-p, richard-kunert) +- Russia fixes (tserekh) +- Ireland fixes (chiuczek) +- France fix (mborsetti) +- Mexico fix (mborsetti) +- Singapore 2022 fix (mborsetti) +- Fix on occasional pop_named exception (mborsetti) +- convertdate fallback if hijri-converter not available (mborsetti) +- enabled Travis tests for python3.9 (mborsetti) +- added flake8 to unittests (mborsetti) Version 0.10.3 diff --git a/README.rst b/README.rst index 6865d119a..638e0e50a 100644 --- a/README.rst +++ b/README.rst @@ -110,7 +110,8 @@ Bulgaria BG/BLG None Burundi BI/BDI None Canada CA/CAN prov = AB, BC, MB, NB, NL, NS, NT, NU, **ON** (default), PE, QC, SK, YU -Chile CL/CHL None +Chile CL/CHL state = AI, AN, AP, AR, AT, BI, CO, LI, LL, LR, MA, ML, NB, + RM, TA, VS Colombia CO/COL None Croatia HR/HRV None Czechia CZ/CZE None @@ -122,7 +123,7 @@ England None Estonia EE/EST None EuropeanCentralBank ECB/TAR Trans-European Automated Real-time Gross Settlement (TARGET2) Finland FI/FIN None -France FRA **Métropole** (default), Alsace-Moselle, Guadeloupe, Guyane, +France FR/FRA **Métropole** (default), Alsace-Moselle, Guadeloupe, Guyane, Martinique, Mayotte, Nouvelle-Calédonie, La Réunion, Polynésie Française, Saint-Barthélémy, Saint-Martin, Wallis-et-Futuna @@ -177,7 +178,7 @@ Switzerland CH/CHE prov = AG, AR, AI, BL, BS, BE, FR, GE, GL, GR, JU, Turkey TR/TUR None Ukraine UA/UKR None UnitedArabEmirates AE/ARE None -UnitedKingdom UK/GB/GBR None +UnitedKingdom GB/GBR/UK None UnitedStates US/USA state = AL, AK, AS, AZ, AR, CA, CO, CT, DE, DC, FL, GA, GU, HI, ID, IL, IN, IA, KS, KY, LA, ME, MD, MH, MA, MI, FM, MN, MS, MO, MT, NE, NV, NH, NJ, NM, NY, NC, ND, MP, diff --git a/holidays/countries/__init__.py b/holidays/countries/__init__.py index 06762b42a..192904bd7 100644 --- a/holidays/countries/__init__.py +++ b/holidays/countries/__init__.py @@ -31,7 +31,7 @@ from .estonia import Estonia, EE, EST from .european_central_bank import EuropeanCentralBank, ECB, TAR from .finland import Finland, FI, FIN -from .france import France, FRA +from .france import France, FR, FRA from .germany import Germany, DE, DEU from .greece import Greece, GR, GRC from .honduras import Honduras, HN, HND diff --git a/holidays/countries/chile.py b/holidays/countries/chile.py index 44d52ea45..d66b71b49 100644 --- a/holidays/countries/chile.py +++ b/holidays/countries/chile.py @@ -14,92 +14,143 @@ from datetime import date from dateutil.easter import easter -from dateutil.relativedelta import relativedelta as rd, FR +from dateutil.relativedelta import relativedelta as rd, MO, FR, SA from holidays.constants import JAN, MAY, JUN, JUL, AUG, SEP, OCT, \ NOV, DEC -from holidays.constants import WED, THU +from holidays.constants import TUE, THU, FRI, SAT, SUN from holidays.holiday_base import HolidayBase class Chile(HolidayBase): # https://www.feriados.cl + # http://www.feriadoschilenos.cl/ (excellent history) # https://es.wikipedia.org/wiki/Anexo:D%C3%ADas_feriados_en_Chile + # ISO 3166-2 codes for the principal subdivisions, called regions + STATES = ['AI', 'AN', 'AP', 'AR', 'AT', 'BI', 'CO', 'LI', 'LL', 'LR', + 'MA', 'ML', 'NB', 'RM', 'TA', 'VS'] + def __init__(self, **kwargs): self.country = 'CL' HolidayBase.__init__(self, **kwargs) def _populate(self, year): - # New Year's Day + # New Year's Day (Law 2.977) self[date(year, JAN, 1)] = "Año Nuevo [New Year's Day]" + # Day after, if it's a Sunday (Law 20.983) + if year > 2016 and date(year, JAN, 1).weekday() == SUN: + self[date(year, JAN, 2)] = "Fiestas Patrias [Holiday]" - # Holy Week - name_fri = "Semana Santa (Viernes Santo) [Holy day (Holy Friday)]" + # Holy Week (Law 2.977) + name_fri = "Semana Santa (Viernes Santo) [Good Friday)]" + name_sat = "Semana Santa (Sábado Santo) [Good Saturday)]" name_easter = 'Día de Pascuas [Easter Day]' self[easter(year) + rd(weekday=FR(-1))] = name_fri + self[easter(year) + rd(weekday=SA(-1))] = name_sat self[easter(year)] = name_easter - # Labor Day - name = "Día del Trabajo [Labour Day]" + # Labor Day (Law 2.200, renamed with Law 18.018) + name = "Día Nacional del Trabajo [Labour Day]" self[date(year, MAY, 1)] = name - # Naval Glories Day - name = "Día de las Glorias Navales [Naval Glories Day]" + # Naval Glories Day (Law 2.977) + name = "Día de las Glorias Navales [Navy Day]" self[date(year, MAY, 21)] = name - # Saint Peter and Saint Paul. + # Saint Peter and Saint Paul (Law 18.432) name = "San Pedro y San Pablo [Saint Peter and Saint Paul]" - self[date(year, JUN, 29)] = name + if year < 2020: + self[date(year, JUN, 29)] = name + else: + # floating Monday holiday (Law 19.668) + if date(year, JUN, 29).weekday() <= THU: + self[date(year, JUN, 29) + rd(date(year, JUN, 29), + weekday=MO(-1))] = name + elif date(year, JUN, 29).weekday() == FRI: + self[date(year, JUN, 29) + rd(weekday=MO)] = name + else: + self[date(year, JUN, 29)] = name + + # Day of Virgin of Carmen (Law 20.148) + if year > 2006: + name = "Virgen del Carmen [Our Lady of Mount Carmel]" + self[date(year, JUL, 16)] = name + + # Day of Assumption of the Virgin (Law 2.977) + name = "Asunción de la Virgen [Assumption of Mary]" + self[date(year, AUG, 15)] = name - # Day of Virgin of Carmen. - name = "Virgen del Carmen [Virgin of Carmen]" - self[date(year, JUL, 16)] = name + # National Holiday Friday preceding Independence Day (Law 20.983) + if year > 2016 and date(year, SEP, 18).weekday() == SAT: + self[date(year, SEP, 17)] = "Fiestas Patrias [Holiday]" - # Day of Assumption of the Virgin - name = "Asunsión de la Virgen [Assumption of the Virgin]" - self[date(year, AUG, 15)] = name + # National Holiday Monday preceding Independence Day (Law 20.215) + if year > 2007 and date(year, SEP, 18).weekday() == TUE: + self[date(year, SEP, 17)] = "Fiestas Patrias [Holiday]" - # Independence Day + # Independence Day (Law 2.977) name = "Día de la Independencia [Independence Day]" self[date(year, SEP, 18)] = name - # Day of Glories of the Army of Chile - name = "Día de las Glorias del Ejército de Chile [Day of " \ - "Glories of the Army of Chile]" + # Day of Glories of the Army of Chile (Law 2.977) + name = "Día de las Glorias del Ejército [Army Day]" self[date(year, SEP, 19)] = name - # National Holidays Ley 20.215 - name = "Fiestas Patrias [National Holidays]" - if year > 2014 and date(year, SEP, 19).weekday() in [WED, THU]: - self[date(year, SEP, 20)] = name - # Day of the Meeting of Two Worlds + # National Holiday Friday following Army Day (Law 20.215) + if year > 2007 and date(year, SEP, 19).weekday() == THU: + self[date(year, SEP, 20)] = "Fiestas Patrias [Holiday]" + + # Day of the Meeting of Two Worlds (Law 3.810) if year < 2010: self[date(year, OCT, 12)] = "Día de la Raza [Columbus day]" - else: + elif year < 2020: self[date(year, OCT, 12)] = "Día del Respeto a la Diversidad"\ " [Day of the Meeting " \ " of Two Worlds]" - - # National Day of the Evangelical and Protestant Churches - name = "Día Nacional de las Iglesias Evangélicas y Protestantes " \ - " [National Day of the " \ - " Evangelical and " \ - " Protestant Churches]" - self[date(year, OCT, 31)] = name - - # All Saints Day + else: + # floating Monday holiday (Law 19.668) + name = ("Día del Descubrimiento de dos Mundos [Columbus Day]") + if date(year, OCT, 12).weekday() <= THU: + self[date(year, OCT, 12) + rd(date(year, OCT, 12), + weekday=MO(-1))] = name + elif date(year, OCT, 12).weekday() == FRI: + self[date(year, OCT, 12) + rd(weekday=MO)] = name + else: + self[date(year, OCT, 12)] = name + + # National Day of the Evangelical and Protestant Churches (Law 20.299) + if year > 2007: + name = ("Día Nacional de las Iglesias Evangélicas y Protestantes " + " [Reformation Day]") + self[date(year, OCT, 31)] = name + + # All Saints Day (Law 2.977) name = "Día de Todos los Santos [All Saints Day]" self[date(year, NOV, 1)] = name - # Immaculate Conception + # Immaculate Conception (Law 2.977) self[date(year, DEC, 8)] = "La Inmaculada Concepción" \ " [Immaculate Conception]" - # Christmas + # Christmas (Law 2.977) self[date(year, DEC, 25)] = "Navidad [Christmas]" + # región de Arica y Parinacota + if self.state == 'AP' and year >= 2020: + # Law 20.663 + self[date(year, JUN, 7)] = ("Asalto y Toma del Morro de Arica" + " [Assault and Capture of Cape Arica]") + + # región de Ñuble + if self.state == 'NB' and year >= 2014: + # Law 20.678 + self[date(year, AUG, 20)] =\ + ("Nacimiento del Prócer de la Independencia" + " (Chillán y Chillán Viejo)" + " [Nativity of Bernardo O'Higgins]") + class CL(Chile): pass diff --git a/holidays/countries/croatia.py b/holidays/countries/croatia.py index 519fe18b2..0136f1e30 100644 --- a/holidays/countries/croatia.py +++ b/holidays/countries/croatia.py @@ -11,18 +11,18 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date +from datetime import date, timedelta from dateutil.easter import easter -from dateutil.relativedelta import relativedelta as rd -from holidays.constants import JAN, MAY, JUN, AUG, OCT, \ - NOV, DEC +from holidays.constants import JAN, MAY, JUN, AUG, OCT, NOV, DEC from holidays.holiday_base import HolidayBase class Croatia(HolidayBase): + # Updated with act 022-03 / 19-01 / 219 of 14 November 2019 + # https://narodne-novine.nn.hr/clanci/sluzbeni/2019_11_110_2212.html # https://en.wikipedia.org/wiki/Public_holidays_in_Croatia def __init__(self, **kwargs): @@ -32,6 +32,7 @@ def __init__(self, **kwargs): def _populate(self, year): # New years self[date(year, JAN, 1)] = "Nova Godina" + # Epiphany self[date(year, JAN, 6)] = "Sveta tri kralja" easter_date = easter(year) @@ -39,23 +40,23 @@ def _populate(self, year): # Easter self[easter_date] = "Uskrs" # Easter Monday - self[easter_date + rd(days=1)] = "Uskršnji ponedjeljak" + self[easter_date + timedelta(days=1)] = "Uskrsni ponedjeljak" # Corpus Christi - self[easter_date + rd(days=60)] = "Tijelovo" + self[easter_date + timedelta(days=60)] = "Tijelovo" # International Workers' Day self[date(year, MAY, 1)] = "Međunarodni praznik rada" + # Statehood day (new) if year >= 2020: - # Statehood day self[date(year, MAY, 30)] = "Dan državnosti" # Anti-fascist struggle day self[date(year, JUN, 22)] = "Dan antifašističke borbe" + # Statehood day (old) if year < 2020: - # Statehood day self[date(year, JUN, 25)] = "Dan državnosti" # Victory and Homeland Thanksgiving Day @@ -64,17 +65,16 @@ def _populate(self, year): # Assumption of Mary self[date(year, AUG, 15)] = "Velika Gospa" + # Independence Day (old) if year < 2020: - # Independence Day self[date(year, OCT, 8)] = "Dan neovisnosti" # All Saints' Day - self[date(year, NOV, 1)] = "Dan svih svetih" + self[date(year, NOV, 1)] = "Svi sveti" if year >= 2020: # Memorial day - self[date(year, NOV, 18)] =\ - "Dan sjećanja na žrtve Domovinskog rata" + self[date(year, NOV, 18)] = "Dan sjećanja" # Christmas day self[date(year, DEC, 25)] = "Božić" diff --git a/holidays/countries/france.py b/holidays/countries/france.py index 8f57f5187..66d995341 100644 --- a/holidays/countries/france.py +++ b/holidays/countries/france.py @@ -123,6 +123,10 @@ def _populate(self, year): self[date(year, DEC, 20)] = "Abolition de l'esclavage" -# FR already exists (Friday), we don't want to mess it up +# *Warning* FR is also used by dateutlis (Friday), so be careful with its use +class FR(France): + pass + + class FRA(France): pass diff --git a/holidays/countries/mexico.py b/holidays/countries/mexico.py index 9a51939b3..e283fdb34 100755 --- a/holidays/countries/mexico.py +++ b/holidays/countries/mexico.py @@ -57,7 +57,8 @@ def _populate(self, year): # Labor Day if year >= 1923: - self[date(year, MAY, 1)] = "Día del Trabajo [Labour Day]" + name = "Día del Trabajo [Labour Day]" + self[date(year, MAY, 1)] = name if self.observed and date(year, MAY, 1).weekday() == SAT: self[date(year, MAY, 1) + rd(days=-1)] = name + " (Observed)" elif self.observed and date(year, MAY, 1).weekday() == SUN: diff --git a/holidays/countries/russia.py b/holidays/countries/russia.py index 8e9352953..41d36c929 100644 --- a/holidays/countries/russia.py +++ b/holidays/countries/russia.py @@ -53,8 +53,12 @@ def _populate(self, year): self[date(year, MAY, 9)] = "День Победы" # Russia's Day self[date(year, JUN, 12)] = "День России" - # Unity Day - self[date(year, NOV, 4)] = "День народного единства" + if year >= 2005: + # Unity Day + self[date(year, NOV, 4)] = "День народного единства" + else: + # October Revolution Day + self[date(year, NOV, 7)] = "День Октябрьской революции" class RU(Russia): diff --git a/holidays/countries/singapore.py b/holidays/countries/singapore.py index ead9e9083..95aa3a78b 100644 --- a/holidays/countries/singapore.py +++ b/holidays/countries/singapore.py @@ -50,27 +50,13 @@ def __init__(self, **kwargs): def _populate(self, year): - def storeholiday(self, hol_date, hol_name): - """ - Function to store the holiday name in the appropriate - date and to implement Section 4(2) of the Holidays Act: - 'if any day specified in the Schedule falls on a Sunday, - the day next following not being itself a public holiday - is declared a public holiday in Singapore.' - """ - if hol_date.weekday() == SUN: - self[hol_date] = hol_name + " [Sunday]" - self[hol_date + rd(days=+1)] = "Monday following " + hol_name - else: - self[hol_date] = hol_name - # New Year's Day - storeholiday(self, date(year, JAN, 1), "New Year's Day") + self[date(year, JAN, 1)] = "New Year's Day" # Chinese New Year (two days) hol_date = self.get_lunar_n_y_date(year) self[hol_date] = "Chinese New Year" - storeholiday(self, hol_date + rd(days=+1), "Chinese New Year") + self[hol_date + rd(days=+1)] = "Chinese New Year" # Hari Raya Puasa # aka Eid al-Fitr @@ -86,22 +72,22 @@ def storeholiday(self, hol_date, hol_name): if year in dates_obs: for date_obs in dates_obs[year]: hol_date = date(year, *date_obs) - storeholiday(self, hol_date, "Hari Raya Puasa") + self[hol_date] = "Hari Raya Puasa" # Second day of Hari Raya Puasa (up to and including 1968) # Removed since we don't have Hari Raya Puasa dates for the # the years <= 1968: # if year <= 1968: - # storeholiday(self, hol_date + rd(days=+1), + # self[hol_date + rd(days=+1), # "Second day of Hari Raya Puasa") else: for date_obs in self.get_hrp_date(year): hol_date = date_obs - storeholiday(self, hol_date, - "Hari Raya Puasa* (*estimated)") + self[hol_date] = "Hari Raya Puasa* (*estimated)" # Second day of Hari Raya Puasa (up to and including 1968) if year <= 1968: - storeholiday(self, hol_date + rd(days=+1), - "Second day of Hari Raya Puasa* (*estimated)") + hol_date += rd(days=+1) + self[hol_date] = ("Second day of Hari Raya Puasa*" + " (*estimated)") # Hari Raya Haji # aka Eid al-Adha @@ -117,13 +103,11 @@ def storeholiday(self, hol_date, hol_name): if year in dates_obs: for date_obs in dates_obs[year]: hol_date = date(year, *date_obs) - storeholiday(self, hol_date, - "Hari Raya Haji") + self[hol_date] = "Hari Raya Haji" else: for date_obs in self.get_hrh_date(year): hol_date = date_obs - storeholiday(self, hol_date, - "Hari Raya Haji* (*estimated)") + self[hol_date] = "Hari Raya Haji* (*estimated)" # Holy Saturday (up to and including 1968) if year <= 1968: @@ -137,7 +121,7 @@ def storeholiday(self, hol_date, hol_name): self[easter(year) + rd(weekday=MO(1))] = "Easter Monday" # Labour Day - storeholiday(self, date(year, MAY, 1), "Labour Day") + self[date(year, MAY, 1)] = "Labour Day" # Vesak Day # date of observance is announced yearly @@ -152,13 +136,13 @@ def storeholiday(self, hol_date, hol_name): 2021: (MAY, 26)} if year in dates_obs: hol_date = date(year, *dates_obs[year]) - storeholiday(self, hol_date, "Vesak Day") + self[hol_date] = "Vesak Day" else: - storeholiday(self, self.get_vesak_date(year), - "Vesak Day* (*estimated; ~10% chance +/- 1 day)") + hol_date = self.get_vesak_date(year) + self[hol_date] = "Vesak Day* (*estimated; ~10% chance +/- 1 day)" # National Day - storeholiday(self, date(year, AUG, 9), "National Day") + self[date(year, AUG, 9)] = "National Day" # Deepavali # aka Diwali @@ -173,17 +157,17 @@ def storeholiday(self, hol_date, hol_name): 2021: (NOV, 4)} if year in dates_obs: hol_date = date(year, *dates_obs[year]) - storeholiday(self, hol_date, "Deepavali") + self[hol_date] = "Deepavali" else: - storeholiday(self, self.get_s_diwali_date(year), - "Deepavali* (*estimated; rarely on day after)") + hol_date = self.get_s_diwali_date(year) + self[hol_date] = "Deepavali* (*estimated; rarely on day after)" # Christmas Day - storeholiday(self, date(year, DEC, 25), "Christmas Day") + self[date(year, DEC, 25)] = "Christmas Day" # Boxing day (up to and including 1968) if year <= 1968: - storeholiday(self, date(year, DEC, 26), "Boxing Day") + self[date(year, DEC, 26)] = "Boxing Day" # Polling Day dates_obs = {2001: (NOV, 3), 2006: (MAY, 6), 2011: (MAY, 7), @@ -197,7 +181,19 @@ def storeholiday(self, hol_date, hol_name): if year == 2015: self[date(2015, AUG, 7)] = "SG50 Public Holiday" - # The below is used to calcluate lunar new year (i.e. Chinese new year) + # Check for holidays that fall on a Sunday and implement Section 4(2) + # of the Holidays Act: "if any day specified in the Schedule falls on + # a Sunday, the day next following not being itself a public holiday + # is declared a public holiday in Singapore." + for (hol_date, hol_name) in list(self.items()): + if hol_date.weekday() == SUN: + self[hol_date] += ' [Sunday]' + in_lieu_date = hol_date + rd(days=+1) + while in_lieu_date in self: + in_lieu_date += rd(days=+1) + self[in_lieu_date] = hol_name + '[In lieu]' + + # The below is used to calculate lunar new year (i.e. Chinese new year) # Code borrowed from Hong Kong entry as of 16-Nov-19 # Should probably be a function available to multiple countries diff --git a/holidays/countries/united_kingdom.py b/holidays/countries/united_kingdom.py index 4054b559d..dfa92fae0 100644 --- a/holidays/countries/united_kingdom.py +++ b/holidays/countries/united_kingdom.py @@ -166,6 +166,8 @@ def _populate(self, year): # Boxing Day name = "Boxing Day" + if self.country == "Ireland": + name = "St. Stephen's Day" self[date(year, DEC, 26)] = name if self.observed and date(year, DEC, 26).weekday() == SAT: self[date(year, DEC, 28)] = name + " (Observed)" diff --git a/holidays/countries/united_states.py b/holidays/countries/united_states.py index 595005e57..428eac781 100644 --- a/holidays/countries/united_states.py +++ b/holidays/countries/united_states.py @@ -452,12 +452,12 @@ def _populate(self, year): # American Indian Heritage Day # Family Day # New Mexico Presidents' Day - if (self.state in ('DE', 'FL', 'NH', 'NC', 'OK', 'TX', 'WV') and + if (self.state in ('CA', 'DE', 'FL', 'NH', 'NC', 'OK', 'TX', 'WV') and year >= 1975) \ or (self.state == 'IN' and year >= 2010) \ or (self.state == 'MD' and year >= 2008) \ or self.state in ('NV', 'NM'): - if self.state in ('DE', 'NH', 'NC', 'OK', 'WV'): + if self.state in ('CA', 'DE', 'NH', 'NC', 'OK', 'WV'): name = "Day After Thanksgiving" elif self.state in ('FL', 'TX'): name = "Friday After Thanksgiving" diff --git a/holidays/holiday_base.py b/holidays/holiday_base.py index 813d51802..8143e4eb4 100644 --- a/holidays/holiday_base.py +++ b/holidays/holiday_base.py @@ -147,7 +147,8 @@ def get_list(self, key): def get_named(self, name): # find all dates matching provided name (accepting partial # strings too, case insensitive), returning them in a list - return [key for key in self if name.lower() in self[key].lower()] + matches = [key for key in self if name.lower() in self[key].lower()] + return matches def pop(self, key, default=None): if default is None: diff --git a/holidays/utils.py b/holidays/utils.py index 591b7d3c7..9f6df874f 100755 --- a/holidays/utils.py +++ b/holidays/utils.py @@ -24,33 +24,37 @@ def CountryHoliday(country, years=[], prov=None, state=None, expand=True, def get_gre_date(year, Hmonth, Hday): """ - returns the gregian date of a given gregorian calendar - yyyy year with Hijari Month & Day - works *only* if hijri-converter library is installed, otherwise a warning - is raised that this holiday is missing. hijri-converter requires - Python >= 3.6 + Returns the gregorian dates within the gregorian year 'year' + of all instances of islamic calendar 'Hmonth' and 'Hday'. + Defaults to using the hijri-converter library if it is installed + otherwise it uses the less-precise convertdate one (which is a + requirement). """ try: from hijri_converter import convert + + Hyear = convert.Gregorian(year, 1, 1).to_hijri().datetuple()[0] + gres = [convert.Hijri(y, Hmonth, Hday).to_gregorian() + for y in range(Hyear - 1, Hyear + 2)] + gre_dates = [date(*gre.datetuple()) + for gre in gres if gre.year == year] + return gre_dates except ImportError: import warnings + from convertdate import islamic def warning_on_one_line(message, category, filename, lineno, file=None, line=None): return filename + ': ' + str(message) + '\n' + warnings.formatwarning = warning_on_one_line - warnings.warn("Error estimating Islamic Holidays." + - "To estimate, install hijri-converter library") - warnings.warn("pip install -U hijri-converter") + warnings.warn("Islamic Holidays estimated using 'convertdate'" + " package.") + warnings.warn("For higher precision, install 'hijri-converter'" + " package: pip install -U hijri-converter") warnings.warn("(see https://hijri-converter.readthedocs.io/ )") - return [] - Hyear = convert.Gregorian(year, 1, 1).to_hijri().datetuple()[0] - gres = [] - gres.append(convert.Hijri(Hyear - 1, Hmonth, Hday).to_gregorian()) - gres.append(convert.Hijri(Hyear, Hmonth, Hday).to_gregorian()) - gres.append(convert.Hijri(Hyear + 1, Hmonth, Hday).to_gregorian()) - gre_dates = [] - for gre in gres: - if gre.year == year: - gre_dates.append(date(*gre.datetuple())) - return gre_dates + Hyear = islamic.from_gregorian(year, 1, 1)[0] + gres = [islamic.to_gregorian(y, Hmonth, Hmonth) + for y in range(Hyear - 1, Hyear + 2)] + gre_dates = [date(*gre) for gre in gres if gre[0] == year] + return gre_dates diff --git a/tests.py b/tests.py index e42044537..5eb642ea7 100644 --- a/tests.py +++ b/tests.py @@ -11,16 +11,30 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) +import os +import sys +import unittest +import warnings +from glob import glob from itertools import product + from datetime import date, datetime, timedelta from dateutil.relativedelta import relativedelta, MO -import unittest -import warnings -import sys +from flake8.api import legacy as flake8 import holidays +class TestFlake8(unittest.TestCase): + + def test_flake8(self): + """Test that we conform to PEP-8.""" + self.style_guide = flake8.get_style_guide(ignore=['I', 'F401', 'W504']) + self.py_files = [y for x in os.walk(os.path.abspath('holidays')) for y in glob(os.path.join(x[0], '*.py'))] + self.report = self.style_guide.check_files(self.py_files) + self.assertEqual(self.report.get_statistics('E'), []) + + class TestBasics(unittest.TestCase): def setUp(self): @@ -1937,6 +1951,7 @@ def test_discovery_day(self): self.assertIn(date(2017, 11, 20), pr_holidays) def test_thanksgiving_day(self): + ca_holidays = holidays.US(state='CA') de_holidays = holidays.US(state='DE') fl_holidays = holidays.US(state='FL') in_holidays = holidays.US(state='IN') @@ -1955,6 +1970,8 @@ def test_thanksgiving_day(self): self.assertNotIn(dt + relativedelta(days=-1), self.holidays) self.assertNotIn(dt + relativedelta(days=+1), self.holidays) self.assertIn(dt + relativedelta(days=+1), de_holidays) + self.assertEqual(ca_holidays.get(dt + relativedelta(days=+1)), + "Day After Thanksgiving") self.assertEqual(de_holidays.get(dt + relativedelta(days=+1)), "Day After Thanksgiving") self.assertEqual(nh_holidays.get(dt + relativedelta(days=+1)), @@ -3974,8 +3991,8 @@ class TestFrance(unittest.TestCase): def setUp(self): self.holidays = holidays.France() - self.prov_holidays = {prov: holidays.France(prov=prov) - for prov in holidays.France.PROVINCES} + self.prov_holidays = {prov: holidays.FR(prov=prov) + for prov in holidays.FRA.PROVINCES} def test_2017(self): self.assertIn(date(2017, 1, 1), self.holidays) @@ -4949,6 +4966,9 @@ def test_2018(self): self.assertIn(date(2018, 11, 1), self.holidays) self.assertIn(date(2018, 12, 25), self.holidays) self.assertIn(date(2018, 12, 26), self.holidays) + + def test_2020_new(self): + self.assertIn(date(2020, 5, 30), self.holidays) self.assertIn(date(2020, 11, 18), self.holidays) @@ -5282,6 +5302,10 @@ class TestRussia(unittest.TestCase): def setUp(self): self.holidays = holidays.RU() + + def test_before_2005(self): + self.assertIn(date(2004, 11, 7), self.holidays) + self.assertNotIn(date(2004, 11, 4), self.holidays) def test_2018(self): # https://en.wikipedia.org/wiki/Public_holidays_in_Russia @@ -5299,6 +5323,7 @@ def test_2018(self): self.assertIn(date(2018, 5, 9), self.holidays) self.assertIn(date(2018, 6, 12), self.holidays) self.assertIn(date(2018, 11, 4), self.holidays) + self.assertNotIn(date(2018, 11, 7), self.holidays) class TestLatvia(unittest.TestCase): @@ -5733,6 +5758,17 @@ def test_fixed_holidays(self): class TestChile(unittest.TestCase): def setUp(self): self.holidays = holidays.Chile() + self.holidays_AP = holidays.CL(state='AP') + self.holidays_NB = holidays.CHL(state='NB') + + def test_2009(self): + self.assertIn(date(2009, 10, 12), self.holidays) + + def test_2017(self): + self.assertIn(date(2017, 1, 2), self.holidays) + + def test_2018(self): + self.assertIn(date(2018, 9, 17), self.holidays) def test_2019(self): # No laborables (sector público) not included @@ -5747,12 +5783,58 @@ def test_2019(self): self.assertIn(date(2019, 9, 18), self.holidays) self.assertIn(date(2019, 9, 19), self.holidays) self.assertIn(date(2019, 9, 20), self.holidays) - self.assertIn(date(2009, 10, 12), self.holidays) self.assertIn(date(2019, 10, 12), self.holidays) self.assertIn(date(2019, 11, 1), self.holidays) self.assertIn(date(2019, 12, 8), self.holidays) self.assertIn(date(2019, 12, 25), self.holidays) + def test_2020(self): + # from https://feriados.cl/2020.htm + self.assertIn(date(2020, 1, 1), self.holidays) + self.assertIn(date(2020, 4, 10), self.holidays) + self.assertIn(date(2020, 4, 11), self.holidays) + self.assertIn(date(2020, 5, 1), self.holidays) + self.assertIn(date(2020, 5, 21), self.holidays) + self.assertIn(date(2020, 6, 29), self.holidays) + self.assertIn(date(2020, 7, 16), self.holidays) + self.assertIn(date(2020, 8, 15), self.holidays) + self.assertIn(date(2020, 9, 18), self.holidays) + self.assertIn(date(2020, 9, 19), self.holidays) + self.assertIn(date(2020, 10, 12), self.holidays) + self.assertIn(date(2020, 10, 31), self.holidays) + self.assertIn(date(2020, 11, 1), self.holidays) + self.assertIn(date(2020, 12, 8), self.holidays) + self.assertIn(date(2020, 12, 25), self.holidays) + self.assertIn(date(2020, 6, 7), self.holidays_AP) + self.assertIn(date(2020, 8, 20), self.holidays_NB) + + def test_2021(self): + # from https://feriados.cl/2021.htm + self.assertIn(date(2021, 1, 1), self.holidays) + self.assertIn(date(2021, 4, 2), self.holidays) + self.assertIn(date(2021, 4, 3), self.holidays) + self.assertIn(date(2021, 5, 1), self.holidays) + self.assertIn(date(2021, 5, 21), self.holidays) + self.assertIn(date(2021, 6, 28), self.holidays) + self.assertIn(date(2021, 7, 16), self.holidays) + self.assertIn(date(2021, 8, 15), self.holidays) + self.assertIn(date(2021, 9, 18), self.holidays) + self.assertIn(date(2021, 9, 19), self.holidays) + self.assertIn(date(2021, 10, 11), self.holidays) + self.assertIn(date(2021, 10, 31), self.holidays) + self.assertIn(date(2021, 11, 1), self.holidays) + self.assertIn(date(2021, 12, 8), self.holidays) + self.assertIn(date(2021, 12, 25), self.holidays) + self.assertIn(date(2021, 6, 7), self.holidays_AP) + self.assertIn(date(2021, 8, 20), self.holidays_NB) + + def test_2024(self): + self.assertIn(date(2024, 10, 12), self.holidays) + + def test_2029(self): + self.assertIn(date(2029, 7, 2), self.holidays) + self.assertIn(date(2029, 10, 15), self.holidays) + class TestDominicanRepublic(unittest.TestCase): def setUp(self): @@ -6529,7 +6611,9 @@ def test_independence_day(self): self.assertIn(date(year, 7, 1), self.holidays) for year in range(1930, 1962): - self.assertNotIn(date(year, 7, 1), self.holidays) + if year != 1958: + # in 1958 it's Eid Al Adha (as estimated by convertdate) + self.assertNotIn(date(year, 7, 1), self.holidays) self.assertIn("Independence Day (Observed)", self.holidays[date(2018, 7, 2)]) @@ -6660,5 +6744,29 @@ def test_AO_holidays(self): self.assertEqual(self.holidays[date(2020,12,25)], "Dia de Natal e da Família") +class TestAngola(unittest.TestCase): + + def setUp(self): + self.holidays = holidays.AO() + + def test_new_years(self): + self.assertIn('1975-01-01', self.holidays) + self.assertIn('2017-01-01', self.holidays) + self.assertIn('2999-01-01', self.holidays) + self.assertIn('2017-01-02', self.holidays) # sunday + + def test_easter(self): + self.assertIn(date(2017, 4, 14), self.holidays) + self.assertIn(date(2020, 4, 10), self.holidays) + self.assertIn(date(1994, 4, 1), self.holidays) + + def test_static(self): + self.assertIn('2004-03-08', self.holidays) + + def test_not_holiday(self): + self.assertNotIn('2016-12-28', self.holidays) + self.assertNotIn('2015-03-02', self.holidays) + + if __name__ == "__main__": unittest.main()