1# -*- coding: utf-8 -*-
2
3#  python-holidays
4#  ---------------
5#  A fast, efficient Python library for generating country, province and state
6#  specific sets of holidays on the fly. It aims to make determining whether a
7#  specific date is a holiday as fast and flexible as possible.
8#
9#  Author:  ryanss <ryanssdev@icloud.com> (c) 2014-2017
10#           dr-prodigy <maurizio.montel@gmail.com> (c) 2017-2019
11#  Website: https://github.com/dr-prodigy/python-holidays
12#  License: MIT (see LICENSE file)
13
14from datetime import date, datetime, timedelta
15from dateutil.easter import easter, EASTER_ORTHODOX
16from dateutil.parser import parse
17from dateutil.relativedelta import relativedelta as rd
18from dateutil.relativedelta import MO, TU, WE, TH, FR, SA, SU
19import inspect
20import six
21import sys
22import warnings
23
24__version__ = '0.9.12'
25
26MON, TUE, WED, THU, FRI, SAT, SUN = range(7)
27WEEKEND = (SAT, SUN)
28
29JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, \
30    NOV, DEC = range(1, 13)
31
32
33class HolidayBase(dict):
34    PROVINCES = []
35
36    def __init__(self, years=[], expand=True, observed=True,
37                 prov=None, state=None):
38        self.observed = observed
39        self.expand = expand
40        if isinstance(years, int):
41            years = [years, ]
42        self.years = set(years)
43        if not getattr(self, 'prov', False):
44            self.prov = prov
45        self.state = state
46        for year in list(self.years):
47            self._populate(year)
48
49    def __setattr__(self, key, value):
50        if key == 'observed' and len(self) > 0:
51            dict.__setattr__(self, key, value)
52            if value is True:
53                # Add (Observed) dates
54                years = list(self.years)
55                self.years = set()
56                self.clear()
57                for year in years:
58                    self._populate(year)
59            else:
60                # Remove (Observed) dates
61                for k, v in list(self.items()):
62                    if v.find("Observed") >= 0:
63                        del self[k]
64        else:
65            return dict.__setattr__(self, key, value)
66
67    def __keytransform__(self, key):
68        if isinstance(key, datetime):
69            key = key.date()
70        elif isinstance(key, date):
71            key = key
72        elif isinstance(key, int) or isinstance(key, float):
73            key = datetime.utcfromtimestamp(key).date()
74        elif isinstance(key, six.string_types):
75            try:
76                key = parse(key).date()
77            except (ValueError, OverflowError):
78                raise ValueError("Cannot parse date from string '%s'" % key)
79        else:
80            raise TypeError("Cannot convert type '%s' to date." % type(key))
81
82        if self.expand and key.year not in self.years:
83            self.years.add(key.year)
84            self._populate(key.year)
85        return key
86
87    def __contains__(self, key):
88        return dict.__contains__(self, self.__keytransform__(key))
89
90    def __getitem__(self, key):
91        if isinstance(key, slice):
92            if not key.start or not key.stop:
93                raise ValueError("Both start and stop must be given.")
94
95            start = self.__keytransform__(key.start)
96            stop = self.__keytransform__(key.stop)
97
98            if key.step is None:
99                step = 1
100            elif isinstance(key.step, timedelta):
101                step = key.step.days
102            elif isinstance(key.step, int):
103                step = key.step
104            else:
105                raise TypeError(
106                    "Cannot convert type '%s' to int." % type(key.step)
107                )
108
109            if step == 0:
110                raise ValueError('Step value must not be zero.')
111
112            date_diff = stop - start
113            if date_diff.days < 0 <= step or date_diff.days >= 0 > step:
114                step *= -1
115
116            days_in_range = []
117            for delta_days in range(0, date_diff.days, step):
118                day = start + timedelta(days=delta_days)
119                try:
120                    dict.__getitem__(
121                        self,
122                        day
123                    )
124                    days_in_range.append(day)
125                except (KeyError):
126                    pass
127            return days_in_range
128        return dict.__getitem__(self, self.__keytransform__(key))
129
130    def __setitem__(self, key, value):
131        if key in self:
132            if self.get(key).find(value) < 0 \
133                    and value.find(self.get(key)) < 0:
134                value = "%s, %s" % (value, self.get(key))
135            else:
136                value = self.get(key)
137        return dict.__setitem__(self, self.__keytransform__(key), value)
138
139    def update(self, *args):
140        args = list(args)
141        for arg in args:
142            if isinstance(arg, dict):
143                for key, value in list(arg.items()):
144                    self[key] = value
145            elif isinstance(arg, list):
146                for item in arg:
147                    self[item] = "Holiday"
148            else:
149                self[arg] = "Holiday"
150
151    def append(self, *args):
152        return self.update(*args)
153
154    def get(self, key, default=None):
155        return dict.get(self, self.__keytransform__(key), default)
156
157    def get_list(self, key):
158        return [h for h in self.get(key, "").split(", ") if h]
159
160    def pop(self, key, default=None):
161        if default is None:
162            return dict.pop(self, self.__keytransform__(key))
163        return dict.pop(self, self.__keytransform__(key), default)
164
165    def __eq__(self, other):
166        return dict.__eq__(self, other) and self.__dict__ == other.__dict__
167
168    def __ne__(self, other):
169        return dict.__ne__(self, other) or self.__dict__ != other.__dict__
170
171    def __add__(self, other):
172        if isinstance(other, int) and other == 0:
173            # Required to sum() list of holidays
174            # sum([h1, h2]) is equivalent to (0 + h1 + h2)
175            return self
176        elif not isinstance(other, HolidayBase):
177            raise TypeError()
178        HolidaySum = createHolidaySum(self, other)
179        country = (getattr(self, 'country', None) or
180                   getattr(other, 'country', None))
181        if self.country and other.country and self.country != other.country:
182            c1 = self.country
183            if not isinstance(c1, list):
184                c1 = [c1]
185            c2 = other.country
186            if not isinstance(c2, list):
187                c2 = [c2]
188            country = c1 + c2
189        prov = getattr(self, 'prov', None) or getattr(other, 'prov', None)
190        if self.prov and other.prov and self.prov != other.prov:
191            p1 = self.prov if isinstance(self.prov, list) else [self.prov]
192            p2 = other.prov if isinstance(other.prov, list) else [other.prov]
193            prov = p1 + p2
194        return HolidaySum(years=(self.years | other.years),
195                          expand=(self.expand or other.expand),
196                          observed=(self.observed or other.observed),
197                          country=country, prov=prov)
198
199    def __radd__(self, other):
200        return self.__add__(other)
201
202    def _populate(self, year):
203        pass
204
205
206def createHolidaySum(h1, h2):
207    class HolidaySum(HolidayBase):
208
209        def __init__(self, country, **kwargs):
210            self.country = country
211            self.holidays = []
212            if getattr(h1, 'holidays', False):
213                for h in h1.holidays:
214                    self.holidays.append(h)
215            else:
216                self.holidays.append(h1)
217            if getattr(h2, 'holidays', False):
218                for h in h2.holidays:
219                    self.holidays.append(h)
220            else:
221                self.holidays.append(h2)
222            HolidayBase.__init__(self, **kwargs)
223
224        def _populate(self, year):
225            for h in self.holidays[::-1]:
226                h._populate(year)
227                self.update(h)
228
229    return HolidaySum
230
231
232def list_supported_countries():
233    """List all supported countries incl. their abbreviation."""
234    return [name for name, obj in
235            inspect.getmembers(sys.modules[__name__], inspect.isclass)
236            if obj.__module__ is __name__]
237
238
239def CountryHoliday(country, years=[], prov=None, state=None, expand=True,
240                   observed=True):
241    try:
242        country_holiday = globals()[country](years=years,
243                                             prov=prov,
244                                             state=state,
245                                             expand=expand,
246                                             observed=observed)
247    except (KeyError):
248        raise KeyError("Country %s not available" % country)
249    return country_holiday
250
251
252class Aruba(HolidayBase):
253    # http://www.gobierno.aw/informacion-tocante-servicio/vakantie-y-dia-di-fiesta_43437/item/dia-di-fiesta_14809.html
254    # https://www.visitaruba.com/about-aruba/national-holidays-and-celebrations/
255
256    def __init__(self, **kwargs):
257        self.country = 'AW'
258        HolidayBase.__init__(self, **kwargs)
259
260    def _populate(self, year):
261        # New Year's Day
262        self[date(year, JAN, 1)] = "Aña Nobo [New Year's Day]"
263
264        # Dia di Betico
265        self[date(year, JAN, 25)] = "Dia Di Betico [Betico Day]"
266
267        # Carnaval Monday
268        self[easter(year) + rd(days=-48)] = "Dialuna di Carnaval \
269            [Carnaval Monday]"
270
271        # Dia di Himno y Bandera
272        self[date(year, MAR, 18)] = "Dia di Himno y Bandera \
273            [National Anthem & Flag Day]"
274
275        # Good Friday
276        self[easter(year) + rd(weekday=FR(-1))] = "Bierna Santo [Good Friday]"
277
278        # Easter Monday
279        self[easter(year) + rd(days=1)] = "Di Dos Dia di Pasco di Resureccion \
280            [Easter Monday]"
281
282        # King's Day
283        if year >= 2014:
284            kings_day = date(year, APR, 27)
285            if kings_day.weekday() == 6:
286                kings_day = kings_day - rd(days=1)
287
288            self[kings_day] = "Aña di Rey [King's Day]"
289
290        # Queen's Day
291        if 1891 <= year <= 2013:
292            queens_day = date(year, APR, 30)
293            if year <= 1948:
294                queens_day = date(year, AUG, 31)
295
296            if queens_day.weekday() == 6:
297                if year < 1980:
298                    queens_day = queens_day + rd(days=1)
299                else:
300                    queens_day = queens_day - rd(days=1)
301
302            self[queens_day] = "Aña di La Reina [Queen's Day]"
303
304        # Labour Day
305        self[date(year, MAY, 1)] = "Dia di Obrero [Labour Day]"
306
307        # Ascension Day
308        self[easter(year) + rd(days=39)] = "Dia di Asuncion [Ascension Day]"
309
310        # Christmas Day
311        self[date(year, DEC, 25)] = "Pasco di Nacemento [Christmas]"
312
313        # Second Christmas
314        self[date(year, DEC, 26)] = "Di Dos Dia di Pasco di \
315            Nacemento [Second Christmas]"
316
317
318class AW(Aruba):
319    pass
320
321
322class Argentina(HolidayBase):
323    # https://www.argentina.gob.ar/interior/feriados
324    # https://es.wikipedia.org/wiki/Anexo:D%C3%ADas_feriados_en_Argentina
325    # http://servicios.lanacion.com.ar/feriados
326    # https://www.clarin.com/feriados/
327
328    def __init__(self, **kwargs):
329        self.country = 'AR'
330        HolidayBase.__init__(self, **kwargs)
331
332    def _populate(self, year):
333        # New Year's Day
334        if not self.observed and date(year, JAN, 1).weekday() in WEEKEND:
335            pass
336        else:
337            self[date(year, JAN, 1)] = "Año Nuevo [New Year's Day]"
338
339        # Carnival days
340        name = "Día de Carnaval [Carnival's Day]"
341        self[easter(year) - rd(days=48)] = name
342        self[easter(year) - rd(days=47)] = name
343
344        # Memory's National Day for the Truth and Justice
345        name = "Día Nacional de la Memoria por la Verdad y la Justicia " \
346               "[Memory's National Day for the Truth and Justice]"
347
348        if not self.observed and date(year, MAR, 24).weekday() in WEEKEND:
349            pass
350        else:
351            self[date(year, MAR, 24)] = name
352
353        # Holy Week
354        name_thu = "Semana Santa (Jueves Santo)  [Holy day (Holy Thursday)]"
355        name_fri = "Semana Santa (Viernes Santo)  [Holy day (Holy Friday)]"
356        name_easter = 'Día de Pascuas [Easter Day]'
357
358        self[easter(year) + rd(weekday=TH(-1))] = name_thu
359        self[easter(year) + rd(weekday=FR(-1))] = name_fri
360
361        if not self.observed and easter(year).weekday() in WEEKEND:
362            pass
363        else:
364            self[easter(year)] = name_easter
365
366        # Veterans Day and the Fallen in the Malvinas War
367        if not self.observed and date(year, APR, 2).weekday() in WEEKEND:
368            pass
369        else:
370            self[date(year, APR, 2)] = "Día del Veterano y de los Caidos " \
371                "en la Guerra de Malvinas [Veterans" \
372                " Day and the Fallen in the" \
373                " Malvinas War]"
374
375        # Labor Day
376        name = "Día del Trabajo [Labour Day]"
377        if not self.observed and date(year, MAY, 1).weekday() in WEEKEND:
378            pass
379        else:
380            self[date(year, MAY, 1)] = name
381
382        # May Revolution Day
383        name = "Día de la Revolucion de Mayo [May Revolution Day]"
384        if not self.observed and date(year, MAY, 25).weekday() in WEEKEND:
385            pass
386        else:
387            self[date(year, MAY, 25)] = name
388
389        # Day Pass to the Immortality of General Martín Miguel de Güemes.
390        name = "Día Pase a la Inmortalidad " \
391               "del General Martín Miguel de Güemes [Day Pass " \
392               "to the Immortality of General Martín Miguel de Güemes]"
393        if not self.observed and date(year, JUN, 17).weekday() in WEEKEND:
394            pass
395        else:
396            self[date(year, JUN, 17)] = name
397
398        # Day Pass to the Immortality of General D. Manuel Belgrano.
399        name = "Día Pase a la Inmortalidad " \
400               "del General D. Manuel Belgrano [Day Pass " \
401               "to the Immortality of General D. Manuel Belgrano]"
402        if not self.observed and date(year, JUN, 20).weekday() in WEEKEND:
403            pass
404        else:
405            self[date(year, JUN, 20)] = name
406
407        # Independence Day
408        name = "Día de la Independencia [Independence Day]"
409        if not self.observed and date(year, JUL, 9).weekday() in WEEKEND:
410            pass
411        else:
412            self[date(year, JUL, 9)] = name
413
414        # Day Pass to the Immortality of General D. José de San Martin
415        name = "Día Pase a la Inmortalidad " \
416               "del General D. José de San Martin [Day Pass " \
417               "to the Immortality of General D. José de San Martin]"
418        if not self.observed and date(year, AUG, 17).weekday() in WEEKEND:
419            pass
420        else:
421            self[date(year, AUG, 17)] = name
422
423        # Respect for Cultural Diversity Day or Columbus day
424        if not self.observed and date(year, OCT, 12).weekday() in WEEKEND:
425            pass
426        elif year < 2010:
427            self[date(year, OCT, 12)] = "Día de la Raza [Columbus day]"
428        else:
429            self[date(year, OCT, 12)] = "Día del Respeto a la Diversidad" \
430                " Cultural [Respect for" \
431                " Cultural Diversity Day]"
432        # National Sovereignty Day
433        name = "Día Nacional de la Soberanía [National Sovereignty Day]"
434        if not self.observed and date(year, NOV, 20).weekday() in WEEKEND:
435            pass
436        elif year >= 2010:
437            self[date(year, NOV, 20)] = name
438
439        # Immaculate Conception
440        if not self.observed and date(year, DEC, 8).weekday() in WEEKEND:
441            pass
442        else:
443            self[date(year, DEC, 8)] = "La Inmaculada Concepción" \
444                " [Immaculate Conception]"
445
446        # Christmas
447        self[date(year, DEC, 25)] = "Navidad [Christmas]"
448
449
450class AR(Argentina):
451    pass
452
453
454class Belarus(HolidayBase):
455    """
456    http://president.gov.by/en/holidays_en/
457    http://www.belarus.by/en/about-belarus/national-holidays
458    """
459
460    def __init__(self, **kwargs):
461        self.country = "BY"
462        HolidayBase.__init__(self, **kwargs)
463
464    def _populate(self, year):
465        # The current set of holidays came into force in 1998
466        # http://laws.newsby.org/documents/ukazp/pos05/ukaz05806.htm
467        if year <= 1998:
468            return
469
470        # New Year's Day
471        self[date(year, JAN, 1)] = "Новый год"
472
473        # Christmas Day (Orthodox)
474        self[date(year, JAN, 7)] = "Рождество Христово " \
475                                   "(православное Рождество)"
476
477        # Women's Day
478        self[date(year, MAR, 8)] = "День женщин"
479
480        # Radunitsa ("Day of Rejoicing")
481        self[easter(year, method=EASTER_ORTHODOX) + rd(days=9)] = "Радуница"
482
483        # Labour Day
484        self[date(year, MAY, 1)] = "Праздник труда"
485
486        # Victory Day
487        self[date(year, MAY, 9)] = "День Победы"
488
489        # Independence Day
490        self[date(year, JUL, 3)] = "День Независимости Республики Беларусь " \
491                                   "(День Республики)"
492
493        # October Revolution Day
494        self[date(year, NOV, 7)] = "День Октябрьской революции"
495
496        # Christmas Day (Catholic)
497        self[date(year, DEC, 25)] = "Рождество Христово " \
498                                    "(католическое Рождество)"
499
500
501class BY(Belarus):
502    pass
503
504
505class Brazil(HolidayBase):
506    """
507    https://pt.wikipedia.org/wiki/Feriados_no_Brasil
508    """
509
510    STATES = ['AC', 'AL', 'AP', 'AM', 'BA', 'CE', 'DF', 'ES', 'GO', 'MA', 'MT',
511              'MS', 'MG', 'PA', 'PB', 'PE', 'PI', 'RJ', 'RN', 'RS', 'RO', 'RR',
512              'SC', 'SP', 'SE', 'TO']
513
514    def __init__(self, **kwargs):
515        self.country = 'BR'
516        HolidayBase.__init__(self, **kwargs)
517
518    def _populate(self, year):
519        # New Year's Day
520        self[date(year, JAN, 1)] = "Ano novo"
521
522        self[date(year, APR, 21)] = "Tiradentes"
523
524        self[date(year, MAY, 1)] = "Dia Mundial do Trabalho"
525
526        self[date(year, SEP, 7)] = "Independência do Brasil"
527
528        self[date(year, OCT, 12)] = "Nossa Senhora Aparecida"
529
530        self[date(year, NOV, 2)] = "Finados"
531
532        self[date(year, NOV, 15)] = "Proclamação da República"
533
534        # Christmas Day
535        self[date(year, DEC, 25)] = "Natal"
536
537        self[easter(year) - rd(days=2)] = "Sexta-feira Santa"
538
539        self[easter(year)] = "Páscoa"
540
541        self[easter(year) + rd(days=60)] = "Corpus Christi"
542
543        quaresma = easter(year) - rd(days=46)
544        self[quaresma] = "Quarta-feira de cinzas (Início da Quaresma)"
545
546        self[quaresma - rd(weekday=TU(-1))] = "Carnaval"
547
548        if self.state == 'AC':
549            self[date(year, JAN, 23)] = "Dia do evangélico"
550            self[date(year, JUN, 15)] = "Aniversário do Acre"
551            self[date(year, SEP, 5)] = "Dia da Amazônia"
552            self[date(year, NOV, 17)] = "Assinatura do Tratado de" \
553                                        " Petrópolis"
554
555        if self.state == 'AL':
556            self[date(year, JUN, 24)] = "São João"
557            self[date(year, JUN, 29)] = "São Pedro"
558            self[date(year, SEP, 16)] = "Emancipação política de Alagoas"
559            self[date(year, NOV, 20)] = "Consciência Negra"
560
561        if self.state == 'AP':
562            self[date(year, MAR, 19)] = "Dia de São José"
563            self[date(year, JUL, 25)] = "São Tiago"
564            self[date(year, OCT, 5)] = "Criação do estado"
565            self[date(year, NOV, 20)] = "Consciência Negra"
566
567        if self.state == 'AM':
568            self[date(year, SEP, 5)] = "Elevação do Amazonas" \
569                " à categoria de província"
570            self[date(year, NOV, 20)] = "Consciência Negra"
571            self[date(year, DEC, 8)] = "Dia de Nossa Senhora da Conceição"
572
573        if self.state == 'BA':
574            self[date(year, JUL, 2)] = "Independência da Bahia"
575
576        if self.state == 'CE':
577            self[date(year, MAR, 19)] = "São José"
578            self[date(year, MAR, 25)] = "Data Magna do Ceará"
579
580        if self.state == 'DF':
581            self[date(year, APR, 21)] = "Fundação de Brasília"
582            self[date(year, NOV, 30)] = "Dia do Evangélico"
583
584        if self.state == 'ES':
585            self[date(year, OCT, 28)] = "Dia do Servidor Público"
586
587        if self.state == 'GO':
588            self[date(year, OCT, 28)] = "Dia do Servidor Público"
589
590        if self.state == 'MA':
591            self[date(year, JUL, 28)] = "Adesão do Maranhão" \
592                " à independência do Brasil"
593            self[date(year, DEC, 8)] = "Dia de Nossa Senhora da Conceição"
594
595        if self.state == 'MT':
596            self[date(year, NOV, 20)] = "Consciência Negra"
597
598        if self.state == 'MS':
599            self[date(year, OCT, 11)] = "Criação do estado"
600
601        if self.state == 'MG':
602            self[date(year, APR, 21)] = "Data Magna de MG"
603
604        if self.state == 'PA':
605            self[date(year, AUG, 15)] = "Adesão do Grão-Pará" \
606                " à independência do Brasil"
607
608        if self.state == 'PB':
609            self[date(year, AUG, 5)] = "Fundação do Estado"
610
611        if self.state == 'PE':
612            self[date(year, MAR, 6)] = "Revolução Pernambucana (Data Magna)"
613            self[date(year, JUN, 24)] = "São João"
614
615        if self.state == 'PI':
616            self[date(year, MAR, 13)] = "Dia da Batalha do Jenipapo"
617            self[date(year, OCT, 19)] = "Dia do Piauí"
618
619        if self.state == 'RJ':
620            self[date(year, APR, 23)] = "Dia de São Jorge"
621            self[date(year, OCT, 28)] = "Dia do Funcionário Público"
622            self[date(year, NOV, 20)] = "Zumbi dos Palmares"
623
624        if self.state == 'RN':
625            self[date(year, JUN, 29)] = "Dia de São Pedro"
626            self[date(year, OCT, 3)] = "Mártires de Cunhaú e Uruaçuu"
627
628        if self.state == 'RS':
629            self[date(year, SEP, 20)] = "Revolução Farroupilha"
630
631        if self.state == 'RO':
632            self[date(year, JAN, 4)] = "Criação do estado"
633            self[date(year, JUN, 18)] = "Dia do Evangélico"
634
635        if self.state == 'RR':
636            self[date(year, OCT, 5)] = "Criação de Roraima"
637
638        if self.state == 'SC':
639            self[date(year, AUG, 11)] = "Criação da capitania," \
640                " separando-se de SP"
641
642        if self.state == 'SP':
643            self[date(year, JUL, 9)] = "Revolução Constitucionalista de 1932"
644
645        if self.state == 'SE':
646            self[date(year, JUL, 8)] = "Autonomia política de Sergipe"
647
648        if self.state == 'TO':
649            self[date(year, JAN, 1)] = "Instalação de Tocantins"
650            self[date(year, SEP, 8)] = "Nossa Senhora da Natividade"
651            self[date(year, OCT, 5)] = "Criação de Tocantins"
652
653
654class BR(Brazil):
655    pass
656
657
658class Bulgaria(HolidayBase):
659    """
660    Official holidays in Bulgaria in their current form. This class does not
661    any return holidays before 1990, as holidays in the People's Republic of
662    Bulgaria and earlier were different.
663
664    Most holidays are fixed and if the date falls on a Saturday or a Sunday,
665    the following Monday is a non-working day. The exceptions are (1) the
666    Easter holidays, which are always a consecutive Friday, Saturday, and
667    Sunday; and (2) the National Awakening Day which, while an official holiday
668    and a non-attendance day for schools, is still a working day.
669
670    Sources (Bulgarian):
671    - http://lex.bg/laws/ldoc/1594373121
672    - https://www.parliament.bg/bg/24
673
674    Sources (English):
675    - https://en.wikipedia.org/wiki/Public_holidays_in_Bulgaria
676    """
677
678    def __init__(self, **kwargs):
679        self.country = 'BG'
680        HolidayBase.__init__(self, **kwargs)
681
682    def _populate(self, year):
683        if year < 1990:
684            return
685
686        # New Year's Day
687        self[date(year, JAN, 1)] = "Нова година"
688
689        # Liberation Day
690        self[date(year, MAR, 3)] = \
691            "Ден на Освобождението на България от османско иго"
692
693        # International Workers' Day
694        self[date(year, MAY, 1)] = \
695            "Ден на труда и на международната работническа солидарност"
696
697        # Saint George's Day
698        self[date(year, MAY, 6)] = \
699            "Гергьовден, Ден на храбростта и Българската армия"
700
701        # Bulgarian Education and Culture and Slavonic Literature Day
702        self[date(year, MAY, 24)] = \
703            "Ден на българската просвета и култура и на славянската писменост"
704
705        # Unification Day
706        self[date(year, SEP, 6)] = "Ден на Съединението"
707
708        # Independence Day
709        self[date(year, SEP, 22)] = "Ден на Независимостта на България"
710
711        # National Awakening Day
712        self[date(year, NOV, 1)] = "Ден на народните будители"
713
714        # Christmas
715        self[date(year, DEC, 24)] = "Бъдни вечер"
716        self[date(year, DEC, 25)] = "Рождество Христово"
717        self[date(year, DEC, 26)] = "Рождество Христово"
718
719        # Easter
720        self[easter(year, method=EASTER_ORTHODOX)-rd(days=2)] = "Велики петък"
721        self[easter(year, method=EASTER_ORTHODOX)-rd(days=1)] = "Велика събота"
722        self[easter(year, method=EASTER_ORTHODOX)] = "Великден"
723
724
725class BG(Bulgaria):
726    pass
727
728
729class Canada(HolidayBase):
730    PROVINCES = ['AB', 'BC', 'MB', 'NB', 'NL', 'NS', 'NT', 'NU', 'ON', 'PE',
731                 'QC', 'SK', 'YU']
732
733    def __init__(self, **kwargs):
734        self.country = 'CA'
735        self.prov = kwargs.pop('prov', 'ON')
736        HolidayBase.__init__(self, **kwargs)
737
738    def _populate(self, year):
739        # New Year's Day
740        if year >= 1867:
741            name = "New Year's Day"
742            self[date(year, JAN, 1)] = name
743            if self.observed and date(year, JAN, 1).weekday() == SUN:
744                self[date(year, JAN, 1) + rd(days=+1)] = name + \
745                    " (Observed)"
746            elif self.observed \
747                    and date(year, JAN, 1).weekday() == SAT:
748                # Add Dec 31st from the previous year without triggering
749                # the entire year to be added
750                expand = self.expand
751                self.expand = False
752                self[date(year, JAN, 1) + rd(days=-1)] = name + \
753                    " (Observed)"
754                self.expand = expand
755            # The next year's observed New Year's Day can be in this year
756            # when it falls on a Friday (Jan 1st is a Saturday)
757            if self.observed and date(year, DEC, 31).weekday() == FRI:
758                self[date(year, DEC, 31)] = name + " (Observed)"
759
760        # Family Day / Louis Riel Day (MB) / Islander Day (PE)
761        # / Heritage Day (NS, YU)
762        if self.prov in ('AB', 'SK', 'ON') and year >= 2008:
763            self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Family Day"
764        elif self.prov in ('AB', 'SK') and year >= 2007:
765            self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Family Day"
766        elif self.prov == 'AB' and year >= 1990:
767            self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Family Day"
768        elif self.prov == 'NB' and year >= 2018:
769            self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Family Day"
770        elif self.prov == 'BC':
771            if year >= 2013 and year <= 2018:
772                self[date(year, FEB, 1) + rd(weekday=MO(+2))] = \
773                    "Family Day"
774            elif year > 2018:
775                self[date(year, FEB, 1) + rd(weekday=MO(+3))] = \
776                    "Family Day"
777        elif self.prov == 'MB' and year >= 2008:
778            self[date(year, FEB, 1) + rd(weekday=MO(+3))] = \
779                "Louis Riel Day"
780        elif self.prov == 'PE' and year >= 2010:
781            self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Islander Day"
782        elif self.prov == 'PE' and year == 2009:
783            self[date(year, FEB, 1) + rd(weekday=MO(+2))] = "Islander Day"
784        elif self.prov == 'NS' and year >= 2015:
785            # http://novascotia.ca/lae/employmentrights/NovaScotiaHeritageDay.asp
786            self[date(year, FEB, 1) + rd(weekday=MO(+3))] = "Heritage Day"
787        elif self.prov == 'YU':
788            # start date?
789            # http://heritageyukon.ca/programs/heritage-day
790            # https://en.wikipedia.org/wiki/Family_Day_(Canada)#Yukon_Heritage_Day
791            # Friday before the last Sunday in February
792            dt = date(year, MAR, 1) + rd(weekday=SU(-1)) + rd(weekday=FR(-1))
793            self[dt] = "Heritage Day"
794
795        # St. Patrick's Day
796        if self.prov == 'NL' and year >= 1900:
797            dt = date(year, MAR, 17)
798            # Nearest Monday to March 17
799            dt1 = date(year, MAR, 17) + rd(weekday=MO(-1))
800            dt2 = date(year, MAR, 17) + rd(weekday=MO(+1))
801            if dt2 - dt <= dt - dt1:
802                self[dt2] = "St. Patrick's Day"
803            else:
804                self[dt1] = "St. Patrick's Day"
805
806        # Good Friday
807        if self.prov != 'QC' and year >= 1867:
808            self[easter(year) + rd(weekday=FR(-1))] = "Good Friday"
809
810        # Easter Monday
811        if self.prov == 'QC' and year >= 1867:
812            self[easter(year) + rd(weekday=MO)] = "Easter Monday"
813
814        # St. George's Day
815        if self.prov == 'NL' and year == 2010:
816            # 4/26 is the Monday closer to 4/23 in 2010
817            # but the holiday was observed on 4/19? Crazy Newfies!
818            self[date(2010, 4, 19)] = "St. George's Day"
819        elif self.prov == 'NL' and year >= 1990:
820            dt = date(year, APR, 23)
821            # Nearest Monday to April 23
822            dt1 = dt + rd(weekday=MO(-1))
823            dt2 = dt + rd(weekday=MO(+1))
824            if dt2 - dt < dt - dt1:
825                self[dt2] = "St. George's Day"
826            else:
827                self[dt1] = "St. George's Day"
828
829        # Victoria Day / National Patriots' Day (QC)
830        if self.prov not in ('NB', 'NS', 'PE', 'NL', 'QC') and year >= 1953:
831            self[date(year, MAY, 24) + rd(weekday=MO(-1))] = "Victoria Day"
832        elif self.prov == 'QC' and year >= 1953:
833            name = "National Patriots' Day"
834            self[date(year, MAY, 24) + rd(weekday=MO(-1))] = name
835
836        # National Aboriginal Day
837        if self.prov == 'NT' and year >= 1996:
838            self[date(year, JUN, 21)] = "National Aboriginal Day"
839
840        # St. Jean Baptiste Day
841        if self.prov == 'QC' and year >= 1925:
842            self[date(year, JUN, 24)] = "St. Jean Baptiste Day"
843            if self.observed and date(year, JUN, 24).weekday() == SUN:
844                self[date(year, JUN, 25)] = "St. Jean Baptiste Day (Observed)"
845
846        # Discovery Day
847        if self.prov == 'NL' and year >= 1997:
848            dt = date(year, JUN, 24)
849            # Nearest Monday to June 24
850            dt1 = dt + rd(weekday=MO(-1))
851            dt2 = dt + rd(weekday=MO(+1))
852            if dt2 - dt <= dt - dt1:
853                self[dt2] = "Discovery Day"
854            else:
855                self[dt1] = "Discovery Day"
856        elif self.prov == 'YU' and year >= 1912:
857            self[date(year, AUG, 1) + rd(weekday=MO(+3))] = "Discovery Day"
858
859        # Canada Day / Memorial Day (NL)
860        if self.prov != 'NL' and year >= 1867:
861            if year >= 1983:
862                name = "Canada Day"
863            else:
864                name = "Dominion Day"
865            self[date(year, JUL, 1)] = name
866            if year >= 1879 and self.observed \
867                    and date(year, JUL, 1).weekday() in WEEKEND:
868                self[date(year, JUL, 1) + rd(weekday=MO)] = name + \
869                    " (Observed)"
870        elif year >= 1867:
871            if year >= 1983:
872                name = "Memorial Day"
873            else:
874                name = "Dominion Day"
875            self[date(year, JUL, 1)] = name
876            if year >= 1879 and self.observed \
877                    and date(year, JUL, 1).weekday() in WEEKEND:
878                self[date(year, JUL, 1) + rd(weekday=MO)] = name + \
879                    " (Observed)"
880
881        # Nunavut Day
882        if self.prov == 'NU' and year >= 2001:
883            self[date(year, JUL, 9)] = "Nunavut Day"
884            if self.observed and date(year, JUL, 9).weekday() == SUN:
885                self[date(year, JUL, 10)] = "Nunavut Day (Observed)"
886        elif self.prov == 'NU' and year == 2000:
887            self[date(2000, 4, 1)] = "Nunavut Day"
888
889        # Civic Holiday
890        if self.prov in ('ON', 'MB', 'NT') and year >= 1900:
891            self[date(year, AUG, 1) + rd(weekday=MO)] = "Civic Holiday"
892        elif self.prov == 'AB' and year >= 1974:
893            # https://en.wikipedia.org/wiki/Civic_Holiday#Alberta
894            self[date(year, AUG, 1) + rd(weekday=MO)] = "Heritage Day"
895        elif self.prov == 'BC' and year >= 1974:
896            # https://en.wikipedia.org/wiki/Civic_Holiday
897            self[date(year, AUG, 1) + rd(weekday=MO)] = \
898                "British Columbia Day"
899        elif self.prov == 'NB' and year >= 1900:
900            # https://en.wikipedia.org/wiki/Civic_Holiday
901            self[date(year, AUG, 1) + rd(weekday=MO)] = "New Brunswick Day"
902        elif self.prov == 'SK' and year >= 1900:
903            # https://en.wikipedia.org/wiki/Civic_Holiday
904            self[date(year, AUG, 1) + rd(weekday=MO)] = "Saskatchewan Day"
905
906        # Labour Day
907        if year >= 1894:
908            self[date(year, SEP, 1) + rd(weekday=MO)] = "Labour Day"
909
910        # Thanksgiving
911        if self.prov not in ('NB', 'NS', 'PE', 'NL') and year >= 1931:
912            if year == 1935:
913                # in 1935, Canadian Thanksgiving was moved due to the General
914                # Election falling on the second Monday of October
915                # 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
916                self[date(1935, 10, 25)] = "Thanksgiving"
917            else:
918                self[date(year, OCT, 1) + rd(weekday=MO(+2))] = \
919                    "Thanksgiving"
920
921        # Remembrance Day
922        name = "Remembrance Day"
923        provinces = ('ON', 'QC', 'NS', 'NL', 'NT', 'PE', 'SK')
924        if self.prov not in provinces and year >= 1931:
925            self[date(year, NOV, 11)] = name
926        elif self.prov in ('NS', 'NL', 'NT', 'PE', 'SK') and year >= 1931:
927            self[date(year, NOV, 11)] = name
928            if self.observed and date(year, NOV, 11).weekday() == SUN:
929                name = name + " (Observed)"
930                self[date(year, NOV, 11) + rd(weekday=MO)] = name
931
932        # Christmas Day
933        if year >= 1867:
934            self[date(year, DEC, 25)] = "Christmas Day"
935            if self.observed \
936                    and date(year, DEC, 25).weekday() == SAT:
937                self[date(year, DEC, 24)] = "Christmas Day (Observed)"
938            elif self.observed \
939                    and date(year, DEC, 25).weekday() == SUN:
940                self[date(year, DEC, 26)] = "Christmas Day (Observed)"
941
942        # Boxing Day
943        if year >= 1867:
944            name = "Boxing Day"
945            name_observed = name + " (Observed)"
946            if self.observed and date(year, DEC, 26).weekday() in WEEKEND:
947                self[date(year, DEC, 26) + rd(weekday=MO)] = name_observed
948            elif self.observed and date(year, DEC, 26).weekday() == 0:
949                self[date(year, DEC, 27)] = name_observed
950            else:
951                self[date(year, DEC, 26)] = name
952
953
954class CA(Canada):
955    pass
956
957
958class Chile(HolidayBase):
959    # https://www.feriados.cl
960    # https://es.wikipedia.org/wiki/Anexo:D%C3%ADas_feriados_en_Chile
961
962    def __init__(self, **kwargs):
963        self.country = 'CL'
964        HolidayBase.__init__(self, **kwargs)
965
966    def _populate(self, year):
967        # New Year's Day
968        self[date(year, JAN, 1)] = "Año Nuevo [New Year's Day]"
969
970        # Holy Week
971        name_fri = "Semana Santa (Viernes Santo)  [Holy day (Holy Friday)]"
972        name_easter = 'Día de Pascuas [Easter Day]'
973
974        self[easter(year) + rd(weekday=FR(-1))] = name_fri
975        self[easter(year)] = name_easter
976
977        # Labor Day
978        name = "Día del Trabajo [Labour Day]"
979        self[date(year, MAY, 1)] = name
980
981        # Naval Glories Day
982        name = "Día de las Glorias Navales [Naval Glories Day]"
983        self[date(year, MAY, 21)] = name
984
985        # Saint Peter and Saint Paul.
986        name = "San Pedro y San Pablo [Saint Peter and Saint Paul]"
987        self[date(year, JUN, 29)] = name
988
989        # Day of Virgin of Carmen.
990        name = "Virgen del Carmen [Virgin of Carmen]"
991        self[date(year, JUL, 16)] = name
992
993        # Day of Assumption of the Virgin
994        name = "Asunsión de la Virgen [Assumption of the Virgin]"
995        self[date(year, AUG, 15)] = name
996
997        # Independence Day
998        name = "Día de la Independencia [Independence Day]"
999        self[date(year, SEP, 18)] = name
1000
1001        # Day of Glories of the Army of Chile
1002        name = "Día de las Glorias del Ejército de Chile [Day of " \
1003               "Glories of the Army of Chile]"
1004        self[date(year, SEP, 19)] = name
1005        # National Holidays Ley 20.215
1006        name = "Fiestas Patrias [National Holidays]"
1007        if year > 2014 and date(year, SEP, 19).weekday() in [WED, THU]:
1008            self[date(year, SEP, 20)] = name
1009
1010        # Day of the Meeting of Two Worlds
1011        if year < 2010:
1012            self[date(year, OCT, 12)] = "Día de la Raza [Columbus day]"
1013        else:
1014            self[date(year, OCT, 12)] = "Día del Respeto a la Diversidad" \
1015                                            " [Day of the Meeting " \
1016                                            " of Two Worlds]"
1017
1018        # National Day of the Evangelical and Protestant Churches
1019        name = "Día Nacional de las Iglesias Evangélicas y Protestantes " \
1020               " [National Day of the " \
1021               " Evangelical and " \
1022               " Protestant Churches]"
1023        self[date(year, OCT, 31)] = name
1024
1025        # All Saints Day
1026        name = "Día de Todos los Santos [All Saints Day]"
1027        self[date(year, NOV, 1)] = name
1028
1029        # Immaculate Conception
1030        self[date(year, DEC, 8)] = "La Inmaculada Concepción" \
1031                                   " [Immaculate Conception]"
1032
1033        # Christmas
1034        self[date(year, DEC, 25)] = "Navidad [Christmas]"
1035
1036
1037class CL(Chile):
1038    pass
1039
1040
1041class Colombia(HolidayBase):
1042    # https://es.wikipedia.org/wiki/Anexo:D%C3%ADas_festivos_en_Colombia
1043
1044    def __init__(self, **kwargs):
1045        self.country = 'CO'
1046        HolidayBase.__init__(self, **kwargs)
1047
1048    def _populate(self, year):
1049
1050        # Fixed date holidays!
1051        # If observed=True and they fall on a weekend they are not observed.
1052        # If observed=False there are 18 holidays
1053
1054        # New Year's Day
1055        if self.observed and date(year, JAN, 1).weekday() in WEEKEND:
1056            pass
1057        else:
1058            self[date(year, JAN, 1)] = "Año Nuevo [New Year's Day]"
1059
1060        # Labor Day
1061        self[date(year, MAY, 1)] = "Día del Trabajo [Labour Day]"
1062
1063        # Independence Day
1064        name = "Día de la Independencia [Independence Day]"
1065        if self.observed and date(year, JUL, 20).weekday() in WEEKEND:
1066            pass
1067        else:
1068            self[date(year, JUL, 20)] = name
1069
1070        # Battle of Boyaca
1071        self[date(year, AUG, 7)] = "Batalla de Boyacá [Battle of Boyacá]"
1072
1073        # Immaculate Conception
1074        if self.observed and date(year, DEC, 8).weekday() in WEEKEND:
1075            pass
1076        else:
1077            self[date(year, DEC, 8)] = "La Inmaculada Concepción" \
1078                " [Immaculate Conception]"
1079
1080        # Christmas
1081        self[date(year, DEC, 25)] = "Navidad [Christmas]"
1082
1083        # Emiliani Law holidays!
1084        # Unless they fall on a Monday they are observed the following monday
1085
1086        #  Epiphany
1087        name = "Día de los Reyes Magos [Epiphany]"
1088        if date(year, JAN, 6).weekday() == MON or not self.observed:
1089            self[date(year, JAN, 6)] = name
1090        else:
1091            self[date(year, JAN, 6) + rd(weekday=MO)] = name + "(Observed)"
1092
1093        # Saint Joseph's Day
1094        name = "Día de San José [Saint Joseph's Day]"
1095        if date(year, MAR, 19).weekday() == MON or not self.observed:
1096            self[date(year, MAR, 19)] = name
1097        else:
1098            self[date(year, MAR, 19) + rd(weekday=MO)] = name + "(Observed)"
1099
1100        # Saint Peter and Saint Paul's Day
1101        name = "San Pedro y San Pablo [Saint Peter and Saint Paul]"
1102        if date(year, JUN, 29).weekday() == MON or not self.observed:
1103            self[date(year, JUN, 29)] = name
1104        else:
1105            self[date(year, JUN, 29) + rd(weekday=MO)] = name + "(Observed)"
1106
1107        # Assumption of Mary
1108        name = "La Asunción [Assumption of Mary]"
1109        if date(year, AUG, 15).weekday() == MON or not self.observed:
1110            self[date(year, AUG, 15)] = name
1111        else:
1112            self[date(year, AUG, 15) + rd(weekday=MO)] = name + "(Observed)"
1113
1114        # Discovery of America
1115        name = "Descubrimiento de América [Discovery of America]"
1116        if date(year, OCT, 12).weekday() == MON or not self.observed:
1117            self[date(year, OCT, 12)] = name
1118        else:
1119            self[date(year, OCT, 12) + rd(weekday=MO)] = name + \
1120                "(Observed)"
1121
1122        # All Saints’ Day
1123        name = "Dia de Todos los Santos [All Saint's Day]"
1124        if date(year, NOV, 1).weekday() == MON or not self.observed:
1125            self[date(year, NOV, 1)] = name
1126        else:
1127            self[date(year, NOV, 1) + rd(weekday=MO)] = name + \
1128                "(Observed)"
1129
1130        # Independence of Cartagena
1131        name = "Independencia de Cartagena [Independence of Cartagena]"
1132        if date(year, NOV, 11).weekday() == MON or not self.observed:
1133            self[date(year, NOV, 11)] = name
1134        else:
1135            self[date(year, NOV, 11) + rd(weekday=MO)] = name + \
1136                "(Observed)"
1137
1138        # Holidays based on Easter
1139
1140        # Maundy Thursday
1141        self[easter(year) + rd(weekday=TH(-1))
1142             ] = "Jueves Santo [Maundy Thursday]"
1143
1144        # Good Friday
1145        self[easter(year) + rd(weekday=FR(-1))
1146             ] = "Viernes Santo [Good Friday]"
1147
1148        # Holidays based on Easter but are observed the following monday
1149        # (unless they occur on a monday)
1150
1151        # Ascension of Jesus
1152        name = "Ascensión del señor [Ascension of Jesus]"
1153        hdate = easter(year) + rd(days=+39)
1154        if hdate.weekday() == MON or not self.observed:
1155            self[hdate] = name
1156        else:
1157            self[hdate + rd(weekday=MO)] = name + "(Observed)"
1158
1159        # Corpus Christi
1160        name = "Corpus Christi [Corpus Christi]"
1161        hdate = easter(year) + rd(days=+60)
1162        if hdate.weekday() == MON or not self.observed:
1163            self[hdate] = name
1164        else:
1165            self[hdate + rd(weekday=MO)] = name + "(Observed)"
1166
1167        # Sacred Heart
1168        name = "Sagrado Corazón [Sacred Heart]"
1169        hdate = easter(year) + rd(days=+68)
1170        if hdate.weekday() == MON or not self.observed:
1171            self[hdate] = name
1172        else:
1173            self[hdate + rd(weekday=MO)] = name + "(Observed)"
1174
1175
1176class CO(Colombia):
1177    pass
1178
1179
1180class Mexico(HolidayBase):
1181
1182    def __init__(self, **kwargs):
1183        self.country = 'MX'
1184        HolidayBase.__init__(self, **kwargs)
1185
1186    def _populate(self, year):
1187        # New Year's Day
1188        name = "Año Nuevo [New Year's Day]"
1189        self[date(year, JAN, 1)] = name
1190        if self.observed and date(year, JAN, 1).weekday() == SUN:
1191            self[date(year, JAN, 1) + rd(days=+1)] = name + " (Observed)"
1192        elif self.observed and date(year, JAN, 1).weekday() == SAT:
1193            # Add Dec 31st from the previous year without triggering
1194            # the entire year to be added
1195            expand = self.expand
1196            self.expand = False
1197            self[date(year, JAN, 1) + rd(days=-1)] = name + " (Observed)"
1198            self.expand = expand
1199        # The next year's observed New Year's Day can be in this year
1200        # when it falls on a Friday (Jan 1st is a Saturday)
1201        if self.observed and date(year, DEC, 31).weekday() == FRI:
1202            self[date(year, DEC, 31)] = name + " (Observed)"
1203
1204        # Constitution Day
1205        name = "Día de la Constitución [Constitution Day]"
1206        if 2006 >= year >= 1917:
1207            self[date(year, FEB, 5)] = name
1208        elif year >= 2007:
1209            self[date(year, FEB, 1) + rd(weekday=MO(+1))] = name
1210
1211        # Benito Juárez's birthday
1212        name = "Natalicio de Benito Juárez [Benito Juárez's birthday]"
1213        if 2006 >= year >= 1917:
1214            self[date(year, MAR, 21)] = name
1215        elif year >= 2007:
1216            self[date(year, MAR, 1) + rd(weekday=MO(+3))] = name
1217
1218        # Labor Day
1219        if year >= 1923:
1220            self[date(year, MAY, 1)] = "Día del Trabajo [Labour Day]"
1221            if self.observed and date(year, MAY, 1).weekday() == SAT:
1222                self[date(year, MAY, 1) + rd(days=-1)] = name + " (Observed)"
1223            elif self.observed and date(year, MAY, 1).weekday() == SUN:
1224                self[date(year, MAY, 1) + rd(days=+1)] = name + " (Observed)"
1225
1226        # Independence Day
1227        name = "Día de la Independencia [Independence Day]"
1228        self[date(year, SEP, 16)] = name
1229        if self.observed and date(year, SEP, 16).weekday() == SAT:
1230            self[date(year, SEP, 16) + rd(days=-1)] = name + \
1231                " (Observed)"
1232        elif self.observed and date(year, SEP, 16).weekday() == SUN:
1233            self[date(year, SEP, 16) + rd(days=+1)] = name + \
1234                " (Observed)"
1235
1236        # Revolution Day
1237        name = "Día de la Revolución [Revolution Day]"
1238        if 2006 >= year >= 1917:
1239            self[date(year, NOV, 20)] = name
1240        elif year >= 2007:
1241            self[date(year, NOV, 1) + rd(weekday=MO(+3))] = name
1242
1243        # Change of Federal Government
1244        # Every six years--next observance 2018
1245        name = "Transmisión del Poder Ejecutivo Federal"
1246        name += " [Change of Federal Government]"
1247        if (2018 - year) % 6 == 0:
1248            self[date(year, DEC, 1)] = name
1249            if self.observed \
1250                    and date(year, DEC, 1).weekday() == SAT:
1251                self[date(year, DEC, 1) + rd(days=-1)] = name + \
1252                    " (Observed)"
1253            elif self.observed \
1254                    and date(year, DEC, 1).weekday() == SUN:
1255                self[date(year, DEC, 1) + rd(days=+1)] = name + \
1256                    " (Observed)"
1257
1258        # Christmas
1259        self[date(year, DEC, 25)] = "Navidad [Christmas]"
1260        if self.observed and date(year, DEC, 25).weekday() == SAT:
1261            self[date(year, DEC, 25) + rd(days=-1)] = name + " (Observed)"
1262        elif self.observed and date(year, DEC, 25).weekday() == SUN:
1263            self[date(year, DEC, 25) + rd(days=+1)] = name + " (Observed)"
1264
1265
1266class MX(Mexico):
1267    pass
1268
1269
1270class Ukraine(HolidayBase):
1271    """
1272    http://zakon1.rada.gov.ua/laws/show/322-08/paran454#n454
1273    """
1274
1275    def __init__(self, **kwargs):
1276        self.country = "UA"
1277        HolidayBase.__init__(self, **kwargs)
1278
1279    def _populate(self, year):
1280        # The current set of holidays came into force in 1991
1281        # But most holiday days was inplemented in 1981
1282        if year < 1918:
1283            return
1284
1285        # New Year's Day
1286        if year >= 1898:
1287            self[date(year, JAN, 1)] = "Новий рік"
1288
1289        # Christmas Day (Orthodox)
1290        if year >= 1991:
1291            self[date(year, JAN, 7)] = "Різдво Христове" \
1292                " (православне)"
1293
1294        # Women's Day
1295        if year > 1965:
1296            self[date(year, MAR, 8)] = "Міжнародний жіночий день"
1297
1298        # Easter
1299        if year >= 1991:
1300            self[easter(year, method=EASTER_ORTHODOX)] = "Пасха" \
1301                                                         " (Великдень)"
1302
1303        # Holy trinity
1304        if year >= 1991:
1305            self[easter(year, method=EASTER_ORTHODOX) + rd(days=49)] = "Трійця"
1306
1307        # Labour Day
1308        if year > 2017:
1309            name = "День праці"
1310        elif 1917 < year <= 2017:
1311            name = "День міжнародної солідарності трудящих"
1312        self[date(year, MAY, 1)] = name
1313
1314        # Labour Day in past
1315        if 1928 < year < 2018:
1316            self[date(year, MAY, 2)] = "День міжнародної солідарності трудящих"
1317
1318        # Victory Day
1319        name = "День перемоги"
1320        if year >= 1965:
1321            self[date(year, MAY, 9)] = name
1322        if 1945 <= year < 1947:
1323            self[date(year, MAY, 9)] = name
1324            self[date(year, SEP, 3)] = "День перемоги над Японією"
1325
1326        # Constitution Day
1327        if year >= 1997:
1328            self[date(year, JUN, 28)] = "День Конституції України"
1329
1330        # Independence Day
1331        name = "День незалежності України"
1332        if year > 1991:
1333            self[date(year, AUG, 24)] = name
1334        elif year == 1991:
1335            self[date(year, JUL, 16)] = name
1336
1337        # Day of the defender of Ukraine
1338        if year >= 2015:
1339            self[date(year, OCT, 14)] = "День захисника України"
1340
1341        # USSR Constitution day
1342        name = "День Конституції СРСР"
1343        if 1981 <= year < 1991:
1344            self[date(year, OCT, 7)] = name
1345        elif 1937 <= year < 1981:
1346            self[date(year, DEC, 5)] = name
1347
1348        # October Revolution
1349        if 1917 < year < 2000:
1350            if year <= 1991:
1351                name = "Річниця Великої Жовтневої" \
1352                       " соціалістичної революції"
1353            else:
1354                name = "Річниця жовтневого перевороту"
1355            self[date(year, NOV, 7)] = name
1356            self[date(year, NOV, 8)] = name
1357
1358        # Christmas Day (Catholic)
1359        if year >= 2017:
1360            self[date(year, DEC, 25)] = "Різдво Христове" \
1361                " (католицьке)"
1362        # USSR holidays
1363        # Bloody_Sunday_(1905)
1364        if 1917 <= year < 1951:
1365            self[date(year, JAN, 22)] = "День пам'яті 9 січня 1905 року"
1366
1367        # Paris_Commune
1368        if 1917 < year < 1929:
1369            self[date(year, MAR, 18)] = "День паризької комуни"
1370
1371
1372class UA(Ukraine):
1373    pass
1374
1375
1376class UnitedStates(HolidayBase):
1377    # https://en.wikipedia.org/wiki/Public_holidays_in_the_United_States
1378
1379    STATES = ['AL', 'AK', 'AS', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL',
1380              'GA', 'GU', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME',
1381              'MD', 'MH', 'MA', 'MI', 'FM', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV',
1382              'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'MP', 'OH', 'OK', 'OR', 'PW',
1383              'PA', 'PR', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'VI',
1384              'WA', 'WV', 'WI', 'WY']
1385
1386    def __init__(self, **kwargs):
1387        self.country = 'US'
1388        HolidayBase.__init__(self, **kwargs)
1389
1390    def _populate(self, year):
1391        # New Year's Day
1392        if year > 1870:
1393            name = "New Year's Day"
1394            self[date(year, JAN, 1)] = name
1395            if self.observed and date(year, JAN, 1).weekday() == SUN:
1396                self[date(year, JAN, 1) + rd(days=+1)] = name + \
1397                    " (Observed)"
1398            elif self.observed \
1399                    and date(year, JAN, 1).weekday() == SAT:
1400                # Add Dec 31st from the previous year without triggering
1401                # the entire year to be added
1402                expand = self.expand
1403                self.expand = False
1404                self[date(year, JAN, 1) + rd(days=-1)] = name + \
1405                    " (Observed)"
1406                self.expand = expand
1407            # The next year's observed New Year's Day can be in this year
1408            # when it falls on a Friday (Jan 1st is a Saturday)
1409            if self.observed and date(year, DEC, 31).weekday() == FRI:
1410                self[date(year, DEC, 31)] = name + " (Observed)"
1411
1412        # Epiphany
1413        if self.state == 'PR':
1414            self[date(year, JAN, 6)] = "Epiphany"
1415
1416        # Three King's Day
1417        if self.state == 'VI':
1418            self[date(year, JAN, 6)] = "Three King's Day"
1419
1420        # Lee Jackson Day
1421        name = "Lee Jackson Day"
1422        if self.state == 'VA' and year >= 2000:
1423            dt = date(year, JAN, 1) + rd(weekday=MO(+3)) + rd(
1424                weekday=FR(-1))
1425            self[dt] = name
1426        elif self.state == 'VA' and year >= 1983:
1427            self[date(year, JAN, 1) + rd(weekday=MO(+3))] = name
1428        elif self.state == 'VA' and year >= 1889:
1429            self[date(year, JAN, 19)] = name
1430
1431        # Inauguration Day
1432        if self.state in ('DC', 'LA', 'MD', 'VA') and year >= 1789:
1433            name = "Inauguration Day"
1434            if (year - 1789) % 4 == 0 and year >= 1937:
1435                self[date(year, JAN, 20)] = name
1436                if date(year, JAN, 20).weekday() == SUN:
1437                    self[date(year, JAN, 21)] = name + " (Observed)"
1438            elif (year - 1789) % 4 == 0:
1439                self[date(year, MAR, 4)] = name
1440                if date(year, MAR, 4).weekday() == SUN:
1441                    self[date(year, MAR, 5)] = name + " (Observed)"
1442
1443        # Martin Luther King, Jr. Day
1444        if year >= 1986:
1445            name = "Martin Luther King, Jr. Day"
1446            if self.state == 'AL':
1447                name = "Robert E. Lee/Martin Luther King Birthday"
1448            elif self.state in ('AS', 'MS'):
1449                name = ("Dr. Martin Luther King Jr. "
1450                        "and Robert E. Lee's Birthdays")
1451            elif self.state in ('AZ', 'NH'):
1452                name = "Dr. Martin Luther King Jr./Civil Rights Day"
1453            elif self.state == 'GA' and year < 2012:
1454                name = "Robert E. Lee's Birthday"
1455            elif self.state == 'ID' and year >= 2006:
1456                name = "Martin Luther King, Jr. - Idaho Human Rights Day"
1457            self[date(year, JAN, 1) + rd(weekday=MO(+3))] = name
1458
1459        # Lincoln's Birthday
1460        name = "Lincoln's Birthday"
1461        if (self.state in ('CT', 'IL', 'IA', 'NJ', 'NY') and year >= 1971) \
1462                or (self.state == 'CA' and 1971 <= year <= 2009):
1463            self[date(year, FEB, 12)] = name
1464            if self.observed \
1465                    and date(year, FEB, 12).weekday() == SAT:
1466                self[date(year, FEB, 11)] = name + " (Observed)"
1467            elif self.observed \
1468                    and date(year, FEB, 12).weekday() == SUN:
1469                self[date(year, FEB, 13)] = name + " (Observed)"
1470
1471        # Susan B. Anthony Day
1472        if (self.state == 'CA' and year >= 2014) \
1473                or (self.state == 'FL' and year >= 2011) \
1474                or (self.state == 'NY' and year >= 2004) \
1475                or (self.state == 'WI' and year >= 1976):
1476            self[date(year, FEB, 15)] = "Susan B. Anthony Day"
1477
1478        # Washington's Birthday
1479        name = "Washington's Birthday"
1480        if self.state == 'AL':
1481            name = "George Washington/Thomas Jefferson Birthday"
1482        elif self.state == 'AS':
1483            name = "George Washington's Birthday and Daisy Gatson Bates Day"
1484        elif self.state in ('PR', 'VI'):
1485            name = "Presidents' Day"
1486        if self.state not in ('DE', 'FL', 'GA', 'NM', 'PR'):
1487            if year > 1970:
1488                self[date(year, FEB, 1) + rd(weekday=MO(+3))] = name
1489            elif year >= 1879:
1490                self[date(year, FEB, 22)] = name
1491        elif self.state == 'GA':
1492            if date(year, DEC, 24).weekday() != WED:
1493                self[date(year, DEC, 24)] = name
1494            else:
1495                self[date(year, DEC, 26)] = name
1496        elif self.state in ('PR', 'VI'):
1497            self[date(year, FEB, 1) + rd(weekday=MO(+3))] = name
1498
1499        # Mardi Gras
1500        if self.state == 'LA' and year >= 1857:
1501            self[easter(year) + rd(days=-47)] = "Mardi Gras"
1502
1503        # Guam Discovery Day
1504        if self.state == 'GU' and year >= 1970:
1505            self[date(year, MAR, 1) + rd(weekday=MO)] = "Guam Discovery Day"
1506
1507        # Casimir Pulaski Day
1508        if self.state == 'IL' and year >= 1978:
1509            self[date(year, MAR, 1) + rd(weekday=MO)] = "Casimir Pulaski Day"
1510
1511        # Texas Independence Day
1512        if self.state == 'TX' and year >= 1874:
1513            self[date(year, MAR, 2)] = "Texas Independence Day"
1514
1515        # Town Meeting Day
1516        if self.state == 'VT' and year >= 1800:
1517            self[date(year, MAR, 1) + rd(weekday=TU)] = "Town Meeting Day"
1518
1519        # Evacuation Day
1520        if self.state == 'MA' and year >= 1901:
1521            name = "Evacuation Day"
1522            self[date(year, MAR, 17)] = name
1523            if date(year, MAR, 17).weekday() in WEEKEND:
1524                self[date(year, MAR, 17) + rd(weekday=MO)] = name + \
1525                    " (Observed)"
1526
1527        # Emancipation Day
1528        if self.state == 'PR':
1529            self[date(year, MAR, 22)] = "Emancipation Day"
1530            if self.observed and date(year, MAR, 22).weekday() == SUN:
1531                self[date(year, MAR, 23)] = "Emancipation Day (Observed)"
1532
1533        # Prince Jonah Kuhio Kalanianaole Day
1534        if self.state == 'HI' and year >= 1949:
1535            name = "Prince Jonah Kuhio Kalanianaole Day"
1536            self[date(year, MAR, 26)] = name
1537            if self.observed and date(year, MAR, 26).weekday() == SAT:
1538                self[date(year, MAR, 25)] = name + " (Observed)"
1539            elif self.observed and date(year, MAR, 26).weekday() == SUN:
1540                self[date(year, MAR, 27)] = name + " (Observed)"
1541
1542        # Steward's Day
1543        name = "Steward's Day"
1544        if self.state == 'AK' and year >= 1955:
1545            self[date(year, APR, 1) + rd(days=-1, weekday=MO(-1))] = name
1546        elif self.state == 'AK' and year >= 1918:
1547            self[date(year, MAR, 30)] = name
1548
1549        # César Chávez Day
1550        name = "César Chávez Day"
1551        if self.state == 'CA' and year >= 1995:
1552            self[date(year, MAR, 31)] = name
1553            if self.observed and date(year, MAR, 31).weekday() == SUN:
1554                self[date(year, APR, 1)] = name + " (Observed)"
1555        elif self.state == 'TX' and year >= 2000:
1556            self[date(year, MAR, 31)] = name
1557
1558        # Transfer Day
1559        if self.state == 'VI':
1560            self[date(year, MAR, 31)] = "Transfer Day"
1561
1562        # Emancipation Day
1563        if self.state == 'DC' and year >= 2005:
1564            name = "Emancipation Day"
1565            self[date(year, APR, 16)] = name
1566            if self.observed and date(year, APR, 16).weekday() == SAT:
1567                self[date(year, APR, 15)] = name + " (Observed)"
1568            elif self.observed and date(year, APR, 16).weekday() == SUN:
1569                self[date(year, APR, 17)] = name + " (Observed)"
1570
1571        # Patriots' Day
1572        if self.state in ('ME', 'MA') and year >= 1969:
1573            self[date(year, APR, 1) + rd(weekday=MO(+3))] = "Patriots' Day"
1574        elif self.state in ('ME', 'MA') and year >= 1894:
1575            self[date(year, APR, 19)] = "Patriots' Day"
1576
1577        # Holy Thursday
1578        if self.state == 'VI':
1579            self[easter(year) + rd(weekday=TH(-1))] = "Holy Thursday"
1580
1581        # Good Friday
1582        if self.state in ('CT', 'DE', 'GU', 'IN', 'KY', 'LA',
1583                          'NJ', 'NC', 'PR', 'TN', 'TX', 'VI'):
1584            self[easter(year) + rd(weekday=FR(-1))] = "Good Friday"
1585
1586        # Easter Monday
1587        if self.state == 'VI':
1588            self[easter(year) + rd(weekday=MO)] = "Easter Monday"
1589
1590        # Confederate Memorial Day
1591        name = "Confederate Memorial Day"
1592        if self.state in ('AL', 'GA', 'MS', 'SC') and year >= 1866:
1593            if self.state == 'GA' and year >= 2016:
1594                name = "State Holiday"
1595            self[date(year, APR, 1) + rd(weekday=MO(+4))] = name
1596        elif self.state == 'TX' and year >= 1931:
1597            self[date(year, JAN, 19)] = name
1598
1599        # San Jacinto Day
1600        if self.state == 'TX' and year >= 1875:
1601            self[date(year, APR, 21)] = "San Jacinto Day"
1602
1603        # Arbor Day
1604        if self.state == 'NE' and year >= 1989:
1605            self[date(year, APR, 30) + rd(weekday=FR(-1))] = "Arbor Day"
1606        elif self.state == 'NE' and year >= 1875:
1607            self[date(year, APR, 22)] = "Arbor Day"
1608
1609        # Primary Election Day
1610        if self.state == 'IN' and \
1611                ((year >= 2006 and year % 2 == 0) or year >= 2015):
1612            dt = date(year, MAY, 1) + rd(weekday=MO)
1613            self[dt + rd(days=+1)] = "Primary Election Day"
1614
1615        # Truman Day
1616        if self.state == 'MO' and year >= 1949:
1617            name = "Truman Day"
1618            self[date(year, MAY, 8)] = name
1619            if self.observed and date(year, MAY, 8).weekday() == SAT:
1620                self[date(year, MAY, 7)] = name + " (Observed)"
1621            elif self.observed and date(year, MAY, 8).weekday() == SUN:
1622                self[date(year, MAY, 10)] = name + " (Observed)"
1623
1624        # Memorial Day
1625        if year > 1970:
1626            self[date(year, MAY, 31) + rd(weekday=MO(-1))] = "Memorial Day"
1627        elif year >= 1888:
1628            self[date(year, MAY, 30)] = "Memorial Day"
1629
1630        # Jefferson Davis Birthday
1631        name = "Jefferson Davis Birthday"
1632        if self.state == 'AL' and year >= 1890:
1633            self[date(year, JUN, 1) + rd(weekday=MO)] = name
1634
1635        # Kamehameha Day
1636        if self.state == 'HI' and year >= 1872:
1637            self[date(year, JUN, 11)] = "Kamehameha Day"
1638            if self.observed and year >= 2011:
1639                if date(year, JUN, 11).weekday() == SAT:
1640                    self[date(year, JUN, 10)] = "Kamehameha Day (Observed)"
1641                elif date(year, JUN, 11).weekday() == SUN:
1642                    self[date(year, JUN, 12)] = "Kamehameha Day (Observed)"
1643
1644        # Emancipation Day In Texas
1645        if self.state == 'TX' and year >= 1980:
1646            self[date(year, JUN, 19)] = "Emancipation Day In Texas"
1647
1648        # West Virginia Day
1649        name = "West Virginia Day"
1650        if self.state == 'WV' and year >= 1927:
1651            self[date(year, JUN, 20)] = name
1652            if self.observed and date(year, JUN, 20).weekday() == SAT:
1653                self[date(year, JUN, 19)] = name + " (Observed)"
1654            elif self.observed and date(year, JUN, 20).weekday() == SUN:
1655                self[date(year, JUN, 21)] = name + " (Observed)"
1656
1657        # Emancipation Day in US Virgin Islands
1658        if self.state == 'VI':
1659            self[date(year, JUL, 3)] = "Emancipation Day"
1660
1661        # Independence Day
1662        if year > 1870:
1663            name = "Independence Day"
1664            self[date(year, JUL, 4)] = name
1665            if self.observed and date(year, JUL, 4).weekday() == SAT:
1666                self[date(year, JUL, 4) + rd(days=-1)] = name + " (Observed)"
1667            elif self.observed and date(year, JUL, 4).weekday() == SUN:
1668                self[date(year, JUL, 4) + rd(days=+1)] = name + " (Observed)"
1669
1670        # Liberation Day (Guam)
1671        if self.state == 'GU' and year >= 1945:
1672            self[date(year, JUL, 21)] = "Liberation Day (Guam)"
1673
1674        # Pioneer Day
1675        if self.state == 'UT' and year >= 1849:
1676            name = "Pioneer Day"
1677            self[date(year, JUL, 24)] = name
1678            if self.observed and date(year, JUL, 24).weekday() == SAT:
1679                self[date(year, JUL, 24) + rd(days=-1)] = name + " (Observed)"
1680            elif self.observed and date(year, JUL, 24).weekday() == SUN:
1681                self[date(year, JUL, 24) + rd(days=+1)] = name + " (Observed)"
1682
1683        # Constitution Day
1684        if self.state == 'PR':
1685            self[date(year, JUL, 25)] = "Constitution Day"
1686            if self.observed and date(year, JUL, 25).weekday() == SUN:
1687                self[date(year, JUL, 26)] = "Constitution Day (Observed)"
1688
1689        # Victory Day
1690        if self.state == 'RI' and year >= 1948:
1691            self[date(year, AUG, 1) + rd(weekday=MO(+2))] = "Victory Day"
1692
1693        # Statehood Day (Hawaii)
1694        if self.state == 'HI' and year >= 1959:
1695            self[date(year, AUG, 1) + rd(weekday=FR(+3))] = "Statehood Day"
1696
1697        # Bennington Battle Day
1698        if self.state == 'VT' and year >= 1778:
1699            name = "Bennington Battle Day"
1700            self[date(year, AUG, 16)] = name
1701            if self.observed and date(year, AUG, 16).weekday() == SAT:
1702                self[date(year, AUG, 15)] = name + " (Observed)"
1703            elif self.observed and date(year, AUG, 16).weekday() == SUN:
1704                self[date(year, AUG, 17)] = name + " (Observed)"
1705
1706        # Lyndon Baines Johnson Day
1707        if self.state == 'TX' and year >= 1973:
1708            self[date(year, AUG, 27)] = "Lyndon Baines Johnson Day"
1709
1710        # Labor Day
1711        if year >= 1894:
1712            self[date(year, SEP, 1) + rd(weekday=MO)] = "Labor Day"
1713
1714        # Columbus Day
1715        if self.state not in ('AK', 'AR', 'DE', 'FL', 'HI', 'NV'):
1716            if self.state == 'SD':
1717                name = "Native American Day"
1718            elif self.state == 'VI':
1719                name = "Columbus Day and Puerto Rico Friendship Day"
1720            else:
1721                name = "Columbus Day"
1722            if year >= 1970:
1723                self[date(year, OCT, 1) + rd(weekday=MO(+2))] = name
1724            elif year >= 1937:
1725                self[date(year, OCT, 12)] = name
1726
1727        # Alaska Day
1728        if self.state == 'AK' and year >= 1867:
1729            self[date(year, OCT, 18)] = "Alaska Day"
1730            if self.observed \
1731                    and date(year, OCT, 18).weekday() == SAT:
1732                self[date(year, OCT, 18) + rd(days=-1)] = name + \
1733                    " (Observed)"
1734            elif self.observed \
1735                    and date(year, OCT, 18).weekday() == SUN:
1736                self[date(year, OCT, 18) + rd(days=+1)] = name + \
1737                    " (Observed)"
1738
1739        # Nevada Day
1740        if self.state == 'NV' and year >= 1933:
1741            dt = date(year, OCT, 31)
1742            if year >= 2000:
1743                dt += rd(weekday=FR(-1))
1744            self[dt] = "Nevada Day"
1745            if self.observed and dt.weekday() == SAT:
1746                self[dt + rd(days=-1)] = "Nevada Day (Observed)"
1747            elif self.observed and dt.weekday() == SUN:
1748                self[dt + rd(days=+1)] = "Nevada Day (Observed)"
1749
1750        # Liberty Day
1751        if self.state == 'VI':
1752            self[date(year, NOV, 1)] = "Liberty Day"
1753
1754        # Election Day
1755        if (self.state in ('DE', 'HI', 'IL', 'IN', 'LA',
1756                           'MT', 'NH', 'NJ', 'NY', 'WV') and
1757            year >= 2008 and year % 2 == 0) \
1758                or (self.state in ('IN', 'NY') and year >= 2015):
1759            dt = date(year, NOV, 1) + rd(weekday=MO)
1760            self[dt + rd(days=+1)] = "Election Day"
1761
1762        # All Souls' Day
1763        if self.state == 'GU':
1764            self[date(year, NOV, 2)] = "All Souls' Day"
1765
1766        # Veterans Day
1767        if year > 1953:
1768            name = "Veterans Day"
1769        else:
1770            name = "Armistice Day"
1771        if 1978 > year > 1970:
1772            self[date(year, OCT, 1) + rd(weekday=MO(+4))] = name
1773        elif year >= 1938:
1774            self[date(year, NOV, 11)] = name
1775            if self.observed \
1776                    and date(year, NOV, 11).weekday() == SAT:
1777                self[date(year, NOV, 11) + rd(days=-1)] = name + \
1778                    " (Observed)"
1779            elif self.observed \
1780                    and date(year, NOV, 11).weekday() == SUN:
1781                self[date(year, NOV, 11) + rd(days=+1)] = name + \
1782                    " (Observed)"
1783
1784        # Discovery Day
1785        if self.state == 'PR':
1786            self[date(year, NOV, 19)] = "Discovery Day"
1787            if self.observed and date(year, NOV, 19).weekday() == SUN:
1788                self[date(year, NOV, 20)] = "Discovery Day (Observed)"
1789
1790        # Thanksgiving
1791        if year > 1870:
1792            self[date(year, NOV, 1) + rd(weekday=TH(+4))] = "Thanksgiving"
1793
1794        # Day After Thanksgiving
1795        # Friday After Thanksgiving
1796        # Lincoln's Birthday
1797        # American Indian Heritage Day
1798        # Family Day
1799        # New Mexico Presidents' Day
1800        if (self.state in ('DE', 'FL', 'NH', 'NC', 'OK', 'TX', 'WV') and
1801            year >= 1975) \
1802                or (self.state == 'IN' and year >= 2010) \
1803                or (self.state == 'MD' and year >= 2008) \
1804                or self.state in ('NV', 'NM'):
1805            if self.state in ('DE', 'NH', 'NC', 'OK', 'WV'):
1806                name = "Day After Thanksgiving"
1807            elif self.state in ('FL', 'TX'):
1808                name = "Friday After Thanksgiving"
1809            elif self.state == 'IN':
1810                name = "Lincoln's Birthday"
1811            elif self.state == 'MD' and year >= 2008:
1812                name = "American Indian Heritage Day"
1813            elif self.state == 'NV':
1814                name = "Family Day"
1815            elif self.state == 'NM':
1816                name = "Presidents' Day"
1817            dt = date(year, NOV, 1) + rd(weekday=TH(+4))
1818            self[dt + rd(days=+1)] = name
1819
1820        # Robert E. Lee's Birthday
1821        if self.state == 'GA' and year >= 1986:
1822            if year >= 2016:
1823                name = "State Holiday"
1824            else:
1825                name = "Robert E. Lee's Birthday"
1826            self[date(year, NOV, 29) + rd(weekday=FR(-1))] = name
1827
1828        # Lady of Camarin Day
1829        if self.state == 'GU':
1830            self[date(year, DEC, 8)] = "Lady of Camarin Day"
1831
1832        # Christmas Eve
1833        if self.state == 'AS' or \
1834                (self.state in ('KS', 'MI', 'NC') and year >= 2013) or \
1835                (self.state == 'TX' and year >= 1981) or \
1836                (self.state == 'WI' and year >= 2012):
1837            name = "Christmas Eve"
1838            self[date(year, DEC, 24)] = name
1839            name = name + " (Observed)"
1840            # If on Friday, observed on Thursday
1841            if self.observed and date(year, DEC, 24).weekday() == FRI:
1842                self[date(year, DEC, 24) + rd(days=-1)] = name
1843            # If on Saturday or Sunday, observed on Friday
1844            elif self.observed \
1845                    and date(year, DEC, 24).weekday() in WEEKEND:
1846                self[date(year, DEC, 24) + rd(weekday=FR(-1))] = name
1847
1848        # Christmas Day
1849        if year > 1870:
1850            name = "Christmas Day"
1851            self[date(year, DEC, 25)] = "Christmas Day"
1852            if self.observed \
1853                    and date(year, DEC, 25).weekday() == SAT:
1854                self[date(year, DEC, 25) + rd(days=-1)] = name + \
1855                    " (Observed)"
1856            elif self.observed \
1857                    and date(year, DEC, 25).weekday() == SUN:
1858                self[date(year, DEC, 25) + rd(days=+1)] = name + \
1859                    " (Observed)"
1860
1861        # Day After Christmas
1862        if self.state == 'NC' and year >= 2013:
1863            name = "Day After Christmas"
1864            self[date(year, DEC, 26)] = name
1865            name = name + " (Observed)"
1866            # If on Saturday or Sunday, observed on Monday
1867            if self.observed and date(year, DEC, 26).weekday() in WEEKEND:
1868                self[date(year, DEC, 26) + rd(weekday=MO)] = name
1869            # If on Monday, observed on Tuesday
1870            elif self.observed \
1871                    and date(year, DEC, 26).weekday() == MON:
1872                self[date(year, DEC, 26) + rd(days=+1)] = name
1873        elif self.state == 'TX' and year >= 1981:
1874            self[date(year, DEC, 26)] = "Day After Christmas"
1875        elif self.state == 'VI':
1876            self[date(year, DEC, 26)] = "Christmas Second Day"
1877
1878        # New Year's Eve
1879        if (self.state in ('KY', 'MI') and year >= 2013) or \
1880                (self.state == 'WI' and year >= 2012):
1881            name = "New Year's Eve"
1882            self[date(year, DEC, 31)] = name
1883            if self.observed \
1884                    and date(year, DEC, 31).weekday() == SAT:
1885                self[date(year, DEC, 30)] = name + " (Observed)"
1886
1887
1888class US(UnitedStates):
1889    pass
1890
1891
1892class NewZealand(HolidayBase):
1893    PROVINCES = ['NTL', 'AUK', 'TKI', 'HKB', 'WGN', 'MBH', 'NSN', 'CAN',
1894                 'STC', 'WTL', 'OTA', 'STL', 'CIT']
1895
1896    def __init__(self, **kwargs):
1897        self.country = 'NZ'
1898        HolidayBase.__init__(self, **kwargs)
1899
1900    def _populate(self, year):
1901        # Bank Holidays Act 1873
1902        # The Employment of Females Act 1873
1903        # Factories Act 1894
1904        # Industrial Conciliation and Arbitration Act 1894
1905        # Labour Day Act 1899
1906        # Anzac Day Act 1920, 1949, 1956
1907        # New Zealand Day Act 1973
1908        # Waitangi Day Act 1960, 1976
1909        # Sovereign's Birthday Observance Act 1937, 1952
1910        # Holidays Act 1981, 2003
1911        if year < 1894:
1912            return
1913
1914        # New Year's Day
1915        name = "New Year's Day"
1916        jan1 = date(year, JAN, 1)
1917        self[jan1] = name
1918        if self.observed and jan1.weekday() in WEEKEND:
1919            self[date(year, JAN, 3)] = name + " (Observed)"
1920
1921        name = "Day after New Year's Day"
1922        jan2 = date(year, JAN, 2)
1923        self[jan2] = name
1924        if self.observed and jan2.weekday() in WEEKEND:
1925            self[date(year, JAN, 4)] = name + " (Observed)"
1926
1927        # Waitangi Day
1928        if year > 1973:
1929            name = "New Zealand Day"
1930            if year > 1976:
1931                name = "Waitangi Day"
1932            feb6 = date(year, FEB, 6)
1933            self[feb6] = name
1934            if self.observed and year >= 2014 and feb6.weekday() in WEEKEND:
1935                self[feb6 + rd(weekday=MO)] = name + " (Observed)"
1936
1937        # Easter
1938        self[easter(year) + rd(weekday=FR(-1))] = "Good Friday"
1939        self[easter(year) + rd(weekday=MO)] = "Easter Monday"
1940
1941        # Anzac Day
1942        if year > 1920:
1943            name = "Anzac Day"
1944            apr25 = date(year, APR, 25)
1945            self[apr25] = name
1946            if self.observed and year >= 2014 and apr25.weekday() in WEEKEND:
1947                self[apr25 + rd(weekday=MO)] = name + " (Observed)"
1948
1949        # Sovereign's Birthday
1950        if year >= 1952:
1951            name = "Queen's Birthday"
1952        elif year > 1901:
1953            name = "King's Birthday"
1954        if year == 1952:
1955            self[date(year, JUN, 2)] = name  # Elizabeth II
1956        elif year > 1937:
1957            self[date(year, JUN, 1) + rd(weekday=MO(+1))] = name  # EII & GVI
1958        elif year == 1937:
1959            self[date(year, JUN, 9)] = name  # George VI
1960        elif year == 1936:
1961            self[date(year, JUN, 23)] = name  # Edward VIII
1962        elif year > 1911:
1963            self[date(year, JUN, 3)] = name  # George V
1964        elif year > 1901:
1965            # http://paperspast.natlib.govt.nz/cgi-bin/paperspast?a=d&d=NZH19091110.2.67
1966            self[date(year, NOV, 9)] = name  # Edward VII
1967
1968        # Labour Day
1969        name = "Labour Day"
1970        if year >= 1910:
1971            self[date(year, OCT, 1) + rd(weekday=MO(+4))] = name
1972        elif year > 1899:
1973            self[date(year, OCT, 1) + rd(weekday=WE(+2))] = name
1974
1975        # Christmas Day
1976        name = "Christmas Day"
1977        dec25 = date(year, DEC, 25)
1978        self[dec25] = name
1979        if self.observed and dec25.weekday() in WEEKEND:
1980            self[date(year, DEC, 27)] = name + " (Observed)"
1981
1982        # Boxing Day
1983        name = "Boxing Day"
1984        dec26 = date(year, DEC, 26)
1985        self[dec26] = name
1986        if self.observed and dec26.weekday() in WEEKEND:
1987            self[date(year, DEC, 28)] = name + " (Observed)"
1988
1989        # Province Anniversary Day
1990        if self.prov in ('NTL', 'Northland', 'AUK', 'Auckland'):
1991            if 1963 < year <= 1973 and self.prov in ('NTL', 'Northland'):
1992                name = "Waitangi Day"
1993                dt = date(year, FEB, 6)
1994            else:
1995                name = "Auckland Anniversary Day"
1996                dt = date(year, JAN, 29)
1997            if dt.weekday() in (TUE, WED, THU):
1998                self[dt + rd(weekday=MO(-1))] = name
1999            else:
2000                self[dt + rd(weekday=MO)] = name
2001
2002        elif self.prov in ('TKI', 'Taranaki', 'New Plymouth'):
2003            name = "Taranaki Anniversary Day"
2004            self[date(year, MAR, 1) + rd(weekday=MO(+2))] = name
2005
2006        elif self.prov in ('HKB', "Hawke's Bay"):
2007            name = "Hawke's Bay Anniversary Day"
2008            labour_day = date(year, OCT, 1) + rd(weekday=MO(+4))
2009            self[labour_day + rd(weekday=FR(-1))] = name
2010
2011        elif self.prov in ('WGN', 'Wellington'):
2012            name = "Wellington Anniversary Day"
2013            jan22 = date(year, JAN, 22)
2014            if jan22.weekday() in (TUE, WED, THU):
2015                self[jan22 + rd(weekday=MO(-1))] = name
2016            else:
2017                self[jan22 + rd(weekday=MO)] = name
2018
2019        elif self.prov in ('MBH', 'Marlborough'):
2020            name = "Marlborough Anniversary Day"
2021            labour_day = date(year, OCT, 1) + rd(weekday=MO(+4))
2022            self[labour_day + rd(weeks=1)] = name
2023
2024        elif self.prov in ('NSN', 'Nelson'):
2025            name = "Nelson Anniversary Day"
2026            feb1 = date(year, FEB, 1)
2027            if feb1.weekday() in (TUE, WED, THU):
2028                self[feb1 + rd(weekday=MO(-1))] = name
2029            else:
2030                self[feb1 + rd(weekday=MO)] = name
2031
2032        elif self.prov in ('CAN', 'Canterbury'):
2033            name = "Canterbury Anniversary Day"
2034            showday = date(year, NOV, 1) + rd(weekday=TU) + \
2035                rd(weekday=FR(+2))
2036            self[showday] = name
2037
2038        elif self.prov in ('STC', 'South Canterbury'):
2039            name = "South Canterbury Anniversary Day"
2040            dominion_day = date(year, SEP, 1) + rd(weekday=MO(4))
2041            self[dominion_day] = name
2042
2043        elif self.prov in ('WTL', 'Westland'):
2044            name = "Westland Anniversary Day"
2045            dec1 = date(year, DEC, 1)
2046            # Observance varies?!?!
2047            if year == 2005:  # special case?!?!
2048                self[date(year, DEC, 5)] = name
2049            elif dec1.weekday() in (TUE, WED, THU):
2050                self[dec1 + rd(weekday=MO(-1))] = name
2051            else:
2052                self[dec1 + rd(weekday=MO)] = name
2053
2054        elif self.prov in ('OTA', 'Otago'):
2055            name = "Otago Anniversary Day"
2056            mar23 = date(year, MAR, 23)
2057            # there is no easily determined single day of local observance?!?!
2058            if mar23.weekday() in (TUE, WED, THU):
2059                dt = mar23 + rd(weekday=MO(-1))
2060            else:
2061                dt = mar23 + rd(weekday=MO)
2062            if dt == easter(year) + rd(weekday=MO):  # Avoid Easter Monday
2063                dt += rd(days=1)
2064            self[dt] = name
2065
2066        elif self.prov in ('STL', 'Southland'):
2067            name = "Southland Anniversary Day"
2068            jan17 = date(year, JAN, 17)
2069            if year > 2011:
2070                self[easter(year) + rd(weekday=TU)] = name
2071            else:
2072                if jan17.weekday() in (TUE, WED, THU):
2073                    self[jan17 + rd(weekday=MO(-1))] = name
2074                else:
2075                    self[jan17 + rd(weekday=MO)] = name
2076
2077        elif self.prov in ('CIT', 'Chatham Islands'):
2078            name = "Chatham Islands Anniversary Day"
2079            nov30 = date(year, NOV, 30)
2080            if nov30.weekday() in (TUE, WED, THU):
2081                self[nov30 + rd(weekday=MO(-1))] = name
2082            else:
2083                self[nov30 + rd(weekday=MO)] = name
2084
2085
2086class NZ(NewZealand):
2087    pass
2088
2089
2090class Australia(HolidayBase):
2091    PROVINCES = ['ACT', 'NSW', 'NT', 'QLD', 'SA', 'TAS', 'VIC', 'WA']
2092
2093    def __init__(self, **kwargs):
2094        self.country = 'AU'
2095        self.prov = kwargs.pop('prov', None)
2096        HolidayBase.__init__(self, **kwargs)
2097
2098    def _populate(self, year):
2099        # ACT:  Holidays Act 1958
2100        # NSW:  Public Holidays Act 2010
2101        # NT:   Public Holidays Act 2013
2102        # QLD:  Holidays Act 1983
2103        # SA:   Holidays Act 1910
2104        # TAS:  Statutory Holidays Act 2000
2105        # VIC:  Public Holidays Act 1993
2106        # WA:   Public and Bank Holidays Act 1972
2107
2108        # TODO do more research on history of Aus holidays
2109
2110        # New Year's Day
2111        name = "New Year's Day"
2112        jan1 = date(year, JAN, 1)
2113        self[jan1] = name
2114        if self.observed and jan1.weekday() in WEEKEND:
2115            self[jan1 + rd(weekday=MO)] = name + " (Observed)"
2116
2117        # Australia Day
2118        jan26 = date(year, JAN, 26)
2119        if year >= 1935:
2120            if self.prov == 'NSW' and year < 1946:
2121                name = "Anniversary Day"
2122            else:
2123                name = "Australia Day"
2124            self[jan26] = name
2125            if self.observed and year >= 1946 and jan26.weekday() in WEEKEND:
2126                self[jan26 + rd(weekday=MO)] = name + " (Observed)"
2127        elif year >= 1888 and self.prov != 'SA':
2128            name = "Anniversary Day"
2129            self[jan26] = name
2130
2131        # Adelaide Cup
2132        if self.prov == 'SA':
2133            name = "Adelaide Cup"
2134            if year >= 2006:
2135                # subject to proclamation ?!?!
2136                self[date(year, MAR, 1) + rd(weekday=MO(+2))] = name
2137            else:
2138                self[date(year, MAR, 1) + rd(weekday=MO(+3))] = name
2139
2140        # Canberra Day
2141        # Info from https://www.timeanddate.com/holidays/australia/canberra-day
2142        # and https://en.wikipedia.org/wiki/Canberra_Day
2143        if self.prov == 'ACT' and year >= 1913:
2144            name = "Canberra Day"
2145            if year >= 1913 and year <= 1957:
2146                self[date(year, MAR, 12)] = name
2147            elif year >= 1958 and year <= 2007:
2148                self[date(year, MAR, 1) + rd(weekday=MO(+3))] = name
2149            elif year >= 2008 and year != 2012:
2150                self[date(year, MAR, 1) + rd(weekday=MO(+2))] = name
2151            elif year == 2012:
2152                self[date(year, MAR, 12)] = name
2153
2154        # Easter
2155        self[easter(year) + rd(weekday=FR(-1))] = "Good Friday"
2156        if self.prov in ('ACT', 'NSW', 'NT', 'QLD', 'SA', 'VIC'):
2157            self[easter(year) + rd(weekday=SA(-1))] = "Easter Saturday"
2158        if self.prov in ('ACT', 'NSW', 'QLD', 'VIC'):
2159            self[easter(year)] = "Easter Sunday"
2160        self[easter(year) + rd(weekday=MO)] = "Easter Monday"
2161
2162        # Anzac Day
2163        if year > 1920:
2164            name = "Anzac Day"
2165            apr25 = date(year, APR, 25)
2166            self[apr25] = name
2167            if self.observed:
2168                if apr25.weekday() == SAT and self.prov in ('WA', 'NT'):
2169                    self[apr25 + rd(weekday=MO)] = name + " (Observed)"
2170                elif (apr25.weekday() == SUN and
2171                      self.prov in ('ACT', 'QLD', 'SA', 'WA', 'NT')):
2172                    self[apr25 + rd(weekday=MO)] = name + " (Observed)"
2173
2174        # Western Australia Day
2175        if self.prov == 'WA' and year > 1832:
2176            if year >= 2015:
2177                name = "Western Australia Day"
2178            else:
2179                name = "Foundation Day"
2180            self[date(year, JUN, 1) + rd(weekday=MO(+1))] = name
2181
2182        # Sovereign's Birthday
2183        if year >= 1952:
2184            name = "Queen's Birthday"
2185        elif year > 1901:
2186            name = "King's Birthday"
2187        if year >= 1936:
2188            name = "Queen's Birthday"
2189            if self.prov == 'QLD':
2190                if year == 2012:
2191                    self[date(year, JUN, 11)] = "Queen's Diamond Jubilee"
2192                if year < 2016 and year != 2012:
2193                    dt = date(year, JUN, 1) + rd(weekday=MO(+2))
2194                    self[dt] = name
2195                else:
2196                    dt = date(year, OCT, 1) + rd(weekday=MO)
2197                    self[dt] = name
2198            elif self.prov == 'WA':
2199                # by proclamation ?!?!
2200                self[date(year, OCT, 1) + rd(weekday=MO(-1))] = name
2201            elif self.prov in ('NSW', 'VIC', 'ACT', 'SA', 'NT', 'TAS'):
2202                dt = date(year, JUN, 1) + rd(weekday=MO(+2))
2203                self[dt] = name
2204        elif year > 1911:
2205            self[date(year, JUN, 3)] = name  # George V
2206        elif year > 1901:
2207            self[date(year, NOV, 9)] = name  # Edward VII
2208
2209        # Picnic Day
2210        if self.prov == 'NT':
2211            name = "Picnic Day"
2212            self[date(year, AUG, 1) + rd(weekday=MO)] = name
2213
2214        # Bank Holiday
2215        if self.prov == 'NSW':
2216            if year >= 1912:
2217                name = "Bank Holiday"
2218                self[date(year, 8, 1) + rd(weekday=MO)] = name
2219
2220        # Labour Day
2221        name = "Labour Day"
2222        if self.prov in ('NSW', 'ACT', 'SA'):
2223            self[date(year, OCT, 1) + rd(weekday=MO)] = name
2224        elif self.prov == 'WA':
2225            self[date(year, MAR, 1) + rd(weekday=MO)] = name
2226        elif self.prov == 'VIC':
2227            self[date(year, MAR, 1) + rd(weekday=MO(+2))] = name
2228        elif self.prov == 'QLD':
2229            if 2013 <= year <= 2015:
2230                self[date(year, OCT, 1) + rd(weekday=MO)] = name
2231            else:
2232                self[date(year, MAY, 1) + rd(weekday=MO)] = name
2233        elif self.prov == 'NT':
2234            name = "May Day"
2235            self[date(year, MAY, 1) + rd(weekday=MO)] = name
2236        elif self.prov == 'TAS':
2237            name = "Eight Hours Day"
2238            self[date(year, MAR, 1) + rd(weekday=MO(+2))] = name
2239
2240        # Family & Community Day
2241        if self.prov == 'ACT':
2242            name = "Family & Community Day"
2243            if 2007 <= year <= 2009:
2244                self[date(year, NOV, 1) + rd(weekday=TU)] = name
2245            elif year == 2010:
2246                # first Monday of the September/October school holidays
2247                # moved to the second Monday if this falls on Labour day
2248                # TODO need a formula for the ACT school holidays then
2249                # http://www.cmd.act.gov.au/communication/holidays
2250                self[date(year, SEP, 26)] = name
2251            elif year == 2011:
2252                self[date(year, OCT, 10)] = name
2253            elif year == 2012:
2254                self[date(year, OCT, 8)] = name
2255            elif year == 2013:
2256                self[date(year, SEP, 30)] = name
2257            elif year == 2014:
2258                self[date(year, SEP, 29)] = name
2259            elif year == 2015:
2260                self[date(year, SEP, 28)] = name
2261            elif year == 2016:
2262                self[date(year, SEP, 26)] = name
2263            elif year == 2017:
2264                self[date(year, SEP, 25)] = name
2265
2266        # Reconciliation Day
2267        if self.prov == 'ACT':
2268            name = "Reconciliation Day"
2269            if year >= 2018:
2270                self[date(year, 5, 27) + rd(weekday=MO)] = name
2271
2272        if self.prov == 'VIC':
2273            # Grand Final Day
2274            if year >= 2015:
2275                self[date(year, SEP, 24) + rd(weekday=FR)] = "Grand Final Day"
2276
2277            # Melbourne Cup
2278            self[date(year, NOV, 1) + rd(weekday=TU)] = "Melbourne Cup"
2279
2280        # The Royal Queensland Show (Ekka)
2281        # The Show starts on the first Friday of August - providing this is
2282        # not prior to the 5th - in which case it will begin on the second
2283        # Friday. The Wednesday during the show is a public holiday.
2284        if self.prov == 'QLD':
2285            name = "The Royal Queensland Show"
2286            self[date(year, AUG, 5) + rd(weekday=FR) + rd(weekday=WE)] = \
2287                name
2288
2289        # Christmas Day
2290        name = "Christmas Day"
2291        dec25 = date(year, DEC, 25)
2292        self[dec25] = name
2293        if self.observed and dec25.weekday() in WEEKEND:
2294            self[date(year, DEC, 27)] = name + " (Observed)"
2295
2296        # Boxing Day
2297        if self.prov == 'SA':
2298            name = "Proclamation Day"
2299        else:
2300            name = "Boxing Day"
2301        dec26 = date(year, DEC, 26)
2302        self[dec26] = name
2303        if self.observed and dec26.weekday() in WEEKEND:
2304            self[date(year, DEC, 28)] = name + " (Observed)"
2305
2306
2307class AU(Australia):
2308    pass
2309
2310
2311class Germany(HolidayBase):
2312    """Official holidays for Germany in its current form.
2313
2314    This class doesn't return any holidays before 1990-10-03.
2315
2316    Before that date the current Germany was separated into the "German
2317    Democratic Republic" and the "Federal Republic of Germany" which both had
2318    somewhat different holidays. Since this class is called "Germany" it
2319    doesn't really make sense to include the days from the two former
2320    countries.
2321
2322    Note that Germany doesn't have rules for holidays that happen on a
2323    Sunday. Those holidays are still holiday days but there is no additional
2324    day to make up for the "lost" day.
2325
2326    Also note that German holidays are partly declared by each province there
2327    are some weired edge cases:
2328
2329        - "Mariä Himmelfahrt" is only a holiday in Bavaria (BY) if your
2330          municipality is mostly catholic which in term depends on census data.
2331          Since we don't have this data but most municipalities in Bavaria
2332          *are* mostly catholic, we count that as holiday for whole Bavaria.
2333        - There is an "Augsburger Friedensfest" which only exists in the town
2334          Augsburg. This is excluded for Bavaria.
2335        - "Gründonnerstag" (Thursday before easter) is not a holiday but pupil
2336           don't have to go to school (but only in Baden Württemberg) which is
2337           solved by adjusting school holidays to include this day. It is
2338           excluded from our list.
2339        - "Fronleichnam" is a holiday in certain, explicitly defined
2340          municipalities in Saxony (SN) and Thuringia (TH). We exclude it from
2341          both provinces.
2342    """
2343
2344    PROVINCES = ['BW', 'BY', 'BE', 'BB', 'HB', 'HH', 'HE', 'MV', 'NI', 'NW',
2345                 'RP', 'SL', 'SN', 'ST', 'SH', 'TH']
2346
2347    def __init__(self, **kwargs):
2348        self.country = 'DE'
2349        self.prov = kwargs.pop('prov', None)
2350        HolidayBase.__init__(self, **kwargs)
2351
2352    def _populate(self, year):
2353        if year <= 1989:
2354            return
2355
2356        if year > 1990:
2357
2358            self[date(year, JAN, 1)] = 'Neujahr'
2359
2360            if self.prov in ('BW', 'BY', 'ST'):
2361                self[date(year, JAN, 6)] = 'Heilige Drei Könige'
2362
2363            self[easter(year) - rd(days=2)] = 'Karfreitag'
2364
2365            if self.prov == "BB":
2366                # will always be a Sunday and we have no "observed" rule so
2367                # this is pretty pointless but it's nonetheless an official
2368                # holiday by law
2369                self[easter(year)] = "Ostersonntag"
2370
2371            self[easter(year) + rd(days=1)] = 'Ostermontag'
2372
2373            self[date(year, MAY, 1)] = 'Erster Mai'
2374
2375            if self.prov == "BE" and year == 2020:
2376                self[date(year, MAY, 8)] = \
2377                    "75. Jahrestag der Befreiung vom Nationalsozialismus " \
2378                    "und der Beendigung des Zweiten Weltkriegs in Europa"
2379
2380            self[easter(year) + rd(days=39)] = 'Christi Himmelfahrt'
2381
2382            if self.prov == "BB":
2383                # will always be a Sunday and we have no "observed" rule so
2384                # this is pretty pointless but it's nonetheless an official
2385                # holiday by law
2386                self[easter(year) + rd(days=49)] = "Pfingstsonntag"
2387
2388            self[easter(year) + rd(days=50)] = 'Pfingstmontag'
2389
2390            if self.prov in ('BW', 'BY', 'HE', 'NW', 'RP', 'SL'):
2391                self[easter(year) + rd(days=60)] = 'Fronleichnam'
2392
2393            if self.prov in ('BY', 'SL'):
2394                self[date(year, AUG, 15)] = 'Mariä Himmelfahrt'
2395
2396        self[date(year, OCT, 3)] = 'Tag der Deutschen Einheit'
2397
2398        if self.prov in ('BB', 'MV', 'SN', 'ST', 'TH'):
2399            self[date(year, OCT, 31)] = 'Reformationstag'
2400
2401        if self.prov in ('HB', 'SH', 'NI', 'HH') and year >= 2018:
2402            self[date(year, OCT, 31)] = 'Reformationstag'
2403
2404        # in 2017 all states got the Reformationstag (500th anniversary of
2405        # Luther's thesis)
2406        if year == 2017:
2407            self[date(year, OCT, 31)] = 'Reformationstag'
2408
2409        if self.prov in ('BW', 'BY', 'NW', 'RP', 'SL'):
2410            self[date(year, NOV, 1)] = 'Allerheiligen'
2411
2412        if year <= 1994 or self.prov == 'SN':
2413            # can be calculated as "last wednesday before year-11-23" which is
2414            # why we need to go back two wednesdays if year-11-23 happens to be
2415            # a wednesday
2416            base_data = date(year, NOV, 23)
2417            weekday_delta = WE(-2) if base_data.weekday() == 2 else WE(-1)
2418            self[base_data + rd(weekday=weekday_delta)] = 'Buß- und Bettag'
2419
2420        if year >= 2019:
2421            if self.prov == 'TH':
2422                self[date(year, SEP, 20)] = 'Weltkindertag'
2423
2424            if self.prov == 'BE':
2425                self[date(year, MAR, 8)] = 'Internationaler Frauentag'
2426
2427        self[date(year, DEC, 25)] = 'Erster Weihnachtstag'
2428        self[date(year, DEC, 26)] = 'Zweiter Weihnachtstag'
2429
2430
2431class DE(Germany):
2432    pass
2433
2434
2435class Austria(HolidayBase):
2436    PROVINCES = ['B', 'K', 'N', 'O', 'S', 'ST', 'T', 'V', 'W']
2437
2438    def __init__(self, **kwargs):
2439        self.country = 'AT'
2440        self.prov = kwargs.pop('prov', kwargs.pop('state', 'W'))
2441        HolidayBase.__init__(self, **kwargs)
2442
2443    def _populate(self, year):
2444        # public holidays
2445        self[date(year, JAN, 1)] = "Neujahr"
2446        self[date(year, JAN, 6)] = "Heilige Drei Könige"
2447        self[easter(year) + rd(weekday=MO)] = "Ostermontag"
2448        self[date(year, MAY, 1)] = "Staatsfeiertag"
2449        self[easter(year) + rd(days=39)] = "Christi Himmelfahrt"
2450        self[easter(year) + rd(days=50)] = "Pfingstmontag"
2451        self[easter(year) + rd(days=60)] = "Fronleichnam"
2452        self[date(year, AUG, 15)] = "Mariä Himmelfahrt"
2453        if 1919 <= year <= 1934:
2454            self[date(year, NOV, 12)] = "Nationalfeiertag"
2455        if year >= 1967:
2456            self[date(year, OCT, 26)] = "Nationalfeiertag"
2457        self[date(year, NOV, 1)] = "Allerheiligen"
2458        self[date(year, DEC, 8)] = "Mariä Empfängnis"
2459        self[date(year, DEC, 25)] = "Christtag"
2460        self[date(year, DEC, 26)] = "Stefanitag"
2461
2462
2463class AT(Austria):
2464    pass
2465
2466
2467class Denmark(HolidayBase):
2468    # https://en.wikipedia.org/wiki/Public_holidays_in_Denmark
2469
2470    def __init__(self, **kwargs):
2471        self.country = 'DK'
2472        HolidayBase.__init__(self, **kwargs)
2473
2474    def _populate(self, year):
2475        # Public holidays
2476        self[date(year, JAN, 1)] = "Nytårsdag"
2477        self[easter(year) + rd(weekday=SU(-2))] = "Palmesøndag"
2478        self[easter(year) + rd(weekday=TH(-1))] = "Skærtorsdag"
2479        self[easter(year) + rd(weekday=FR(-1))] = "Langfredag"
2480        self[easter(year)] = "Påskedag"
2481        self[easter(year) + rd(weekday=MO)] = "Anden påskedag"
2482        self[easter(year) + rd(weekday=FR(+4))] = "Store bededag"
2483        self[easter(year) + rd(days=39)] = "Kristi himmelfartsdag"
2484        self[easter(year) + rd(days=49)] = "Pinsedag"
2485        self[easter(year) + rd(days=50)] = "Anden pinsedag"
2486        self[date(year, DEC, 25)] = "Juledag"
2487        self[date(year, DEC, 26)] = "Anden juledag"
2488
2489
2490class DK(Denmark):
2491    pass
2492
2493
2494class UnitedKingdom(HolidayBase):
2495    # https://en.wikipedia.org/wiki/Public_holidays_in_the_United_Kingdom
2496
2497    def __init__(self, **kwargs):
2498        self.country = 'UK'
2499        HolidayBase.__init__(self, **kwargs)
2500
2501    def _populate(self, year):
2502
2503        # New Year's Day
2504        if year >= 1974:
2505            name = "New Year's Day"
2506            self[date(year, JAN, 1)] = name
2507            if self.observed and date(year, JAN, 1).weekday() == SUN:
2508                self[date(year, JAN, 1) + rd(days=+1)] = name + \
2509                    " (Observed)"
2510            elif self.observed \
2511                    and date(year, JAN, 1).weekday() == SAT:
2512                self[date(year, JAN, 1) + rd(days=+2)] = name + \
2513                    " (Observed)"
2514
2515        # New Year Holiday
2516        if self.country in ('UK', 'Scotland'):
2517            name = "New Year Holiday"
2518            if self.country == 'UK':
2519                name += " [Scotland]"
2520            self[date(year, JAN, 2)] = name
2521            if self.observed and date(year, JAN, 2).weekday() in WEEKEND:
2522                self[date(year, JAN, 2) + rd(days=+2)] = name + \
2523                    " (Observed)"
2524            elif self.observed and date(year, JAN, 2).weekday() == MON:
2525                self[date(year, JAN, 2) + rd(days=+1)] = name + \
2526                    " (Observed)"
2527
2528        # St. Patrick's Day
2529        if self.country in ('UK', 'Northern Ireland', 'Ireland'):
2530            name = "St. Patrick's Day"
2531            if self.country == 'UK':
2532                name += " [Northern Ireland]"
2533            self[date(year, MAR, 17)] = name
2534            if self.observed and date(year, MAR, 17).weekday() in WEEKEND:
2535                self[date(year, MAR, 17) + rd(weekday=MO)] = name + \
2536                    " (Observed)"
2537
2538        # Good Friday
2539        if self.country != 'Ireland':
2540            self[easter(year) + rd(weekday=FR(-1))] = "Good Friday"
2541
2542        # Easter Monday
2543        if self.country != 'Scotland':
2544            name = "Easter Monday"
2545            if self.country == 'UK':
2546                name += " [England, Wales, Northern Ireland]"
2547            self[easter(year) + rd(weekday=MO)] = name
2548
2549        # May Day bank holiday (first Monday in May)
2550        if year >= 1978:
2551            name = "May Day"
2552            if year == 2020 and self.country != 'Ireland':
2553                # Moved to Friday to mark 75th anniversary of VE Day.
2554                self[date(year, MAY, 8)] = name
2555            else:
2556                if year == 1995:
2557                    dt = date(year, MAY, 8)
2558                else:
2559                    dt = date(year, MAY, 1)
2560                if dt.weekday() == MON:
2561                    self[dt] = name
2562                elif dt.weekday() == TUE:
2563                    self[dt + rd(days=+6)] = name
2564                elif dt.weekday() == WED:
2565                    self[dt + rd(days=+5)] = name
2566                elif dt.weekday() == THU:
2567                    self[dt + rd(days=+4)] = name
2568                elif dt.weekday() == FRI:
2569                    self[dt + rd(days=+3)] = name
2570                elif dt.weekday() == SAT:
2571                    self[dt + rd(days=+2)] = name
2572                elif dt.weekday() == SUN:
2573                    self[dt + rd(days=+1)] = name
2574
2575        # Spring bank holiday (last Monday in May)
2576        if self.country != 'Ireland':
2577            name = "Spring Bank Holiday"
2578            if year == 2012:
2579                self[date(year, JUN, 4)] = name
2580            elif year >= 1971:
2581                self[date(year, MAY, 31) + rd(weekday=MO(-1))] = name
2582
2583        # June bank holiday (first Monday in June)
2584        if self.country == 'Ireland':
2585            self[date(year, JUN, 1) + rd(weekday=MO)] = "June Bank Holiday"
2586
2587        # TT bank holiday (first Friday in June)
2588        if self.country == 'Isle of Man':
2589            self[date(year, JUN, 1) + rd(weekday=FR)] = "TT Bank Holiday"
2590
2591        # Tynwald Day
2592        if self.country == 'Isle of Man':
2593            self[date(year, JUL, 5)] = "Tynwald Day"
2594
2595        # Battle of the Boyne
2596        if self.country in ('UK', 'Northern Ireland'):
2597            name = "Battle of the Boyne"
2598            if self.country == 'UK':
2599                name += " [Northern Ireland]"
2600            self[date(year, JUL, 12)] = name
2601
2602        # Summer bank holiday (first Monday in August)
2603        if self.country in ('UK', 'Scotland', 'Ireland'):
2604            name = "Summer Bank Holiday"
2605            if self.country == 'UK':
2606                name += " [Scotland]"
2607            self[date(year, AUG, 1) + rd(weekday=MO)] = name
2608
2609        # Late Summer bank holiday (last Monday in August)
2610        if self.country not in ('Scotland', 'Ireland') and year >= 1971:
2611            name = "Late Summer Bank Holiday"
2612            if self.country == 'UK':
2613                name += " [England, Wales, Northern Ireland]"
2614            self[date(year, AUG, 31) + rd(weekday=MO(-1))] = name
2615
2616        # October Bank Holiday (last Monday in October)
2617        if self.country == 'Ireland':
2618            name = "October Bank Holiday"
2619            self[date(year, OCT, 31) + rd(weekday=MO(-1))] = name
2620
2621        # St. Andrew's Day
2622        if self.country in ('UK', 'Scotland'):
2623            name = "St. Andrew's Day"
2624            if self.country == 'UK':
2625                name += " [Scotland]"
2626            self[date(year, NOV, 30)] = name
2627
2628        # Christmas Day
2629        name = "Christmas Day"
2630        self[date(year, DEC, 25)] = name
2631        if self.observed and date(year, DEC, 25).weekday() == SAT:
2632            self[date(year, DEC, 27)] = name + " (Observed)"
2633        elif self.observed and date(year, DEC, 25).weekday() == SUN:
2634            self[date(year, DEC, 27)] = name + " (Observed)"
2635
2636        # Boxing Day
2637        name = "Boxing Day"
2638        self[date(year, DEC, 26)] = name
2639        if self.observed and date(year, DEC, 26).weekday() == SAT:
2640            self[date(year, DEC, 28)] = name + " (Observed)"
2641        elif self.observed and date(year, DEC, 26).weekday() == SUN:
2642            self[date(year, DEC, 28)] = name + " (Observed)"
2643
2644        # Special holidays
2645        if self.country != 'Ireland':
2646            if year == 1977:
2647                self[date(year, JUN, 7)] = "Silver Jubilee of Elizabeth II"
2648            elif year == 1981:
2649                self[date(year, JUL, 29)] = "Wedding of Charles and Diana"
2650            elif year == 1999:
2651                self[date(year, DEC, 31)] = "Millennium Celebrations"
2652            elif year == 2002:
2653                self[date(year, JUN, 3)] = "Golden Jubilee of Elizabeth II"
2654            elif year == 2011:
2655                self[date(year, APR, 29)] = "Wedding of William and" \
2656                    " Catherine"
2657            elif year == 2012:
2658                self[date(year, JUN, 5)] = "Diamond Jubilee of Elizabeth II"
2659
2660
2661class UK(UnitedKingdom):
2662    pass
2663
2664
2665class GB(UnitedKingdom):
2666    pass
2667
2668
2669class England(UnitedKingdom):
2670
2671    def __init__(self, **kwargs):
2672        self.country = 'England'
2673        HolidayBase.__init__(self, **kwargs)
2674
2675
2676class Wales(UnitedKingdom):
2677
2678    def __init__(self, **kwargs):
2679        self.country = 'Wales'
2680        HolidayBase.__init__(self, **kwargs)
2681
2682
2683class Scotland(UnitedKingdom):
2684
2685    def __init__(self, **kwargs):
2686        self.country = 'Scotland'
2687        HolidayBase.__init__(self, **kwargs)
2688
2689
2690class IsleOfMan(UnitedKingdom):
2691
2692    def __init__(self, **kwargs):
2693        self.country = 'Isle of Man'
2694        HolidayBase.__init__(self, **kwargs)
2695
2696
2697class NorthernIreland(UnitedKingdom):
2698
2699    def __init__(self, **kwargs):
2700        self.country = 'Northern Ireland'
2701        HolidayBase.__init__(self, **kwargs)
2702
2703
2704class Ireland(UnitedKingdom):
2705
2706    def __init__(self, **kwargs):
2707        self.country = 'Ireland'
2708        HolidayBase.__init__(self, **kwargs)
2709
2710
2711class IE(Ireland):
2712    pass
2713
2714
2715class Spain(HolidayBase):
2716    PROVINCES = ['AND', 'ARG', 'AST', 'CAN', 'CAM', 'CAL', 'CAT', 'CVA',
2717                 'EXT', 'GAL', 'IBA', 'ICA', 'MAD', 'MUR', 'NAV', 'PVA', 'RIO']
2718
2719    def __init__(self, **kwargs):
2720        self.country = 'ES'
2721        self.prov = kwargs.pop('prov', kwargs.pop('state', ''))
2722        HolidayBase.__init__(self, **kwargs)
2723
2724    def _populate(self, year):
2725        self[date(year, JAN, 1)] = "Año nuevo"
2726        self[date(year, JAN, 6)] = "Epifanía del Señor"
2727        if self.prov and self.prov in ['CVA', 'MUR', 'MAD', 'NAV', 'PVA']:
2728            self[date(year, MAR, 19)] = "San José"
2729        if self.prov and self.prov != 'CAT':
2730            self[easter(year) + rd(weeks=-1, weekday=TH)] = "Jueves Santo"
2731        self[easter(year) + rd(weeks=-1, weekday=FR)] = "Viernes Santo"
2732        if self.prov and self.prov in ['CAT', 'PVA', 'NAV', 'CVA', 'IBA']:
2733            self[easter(year) + rd(weekday=MO)] = "Lunes de Pascua"
2734        self[date(year, MAY, 1)] = "Día del Trabajador"
2735        if self.prov and self.prov in ['CAT', 'GAL']:
2736            self[date(year, JUN, 24)] = "San Juan"
2737        self[date(year, AUG, 15)] = "Asunción de la Virgen"
2738        self[date(year, OCT, 12)] = "Día de la Hispanidad"
2739        self[date(year, NOV, 1)] = "Todos los Santos"
2740        self[date(year, DEC, 6)] = "Día de la constitución Española"
2741        self[date(year, DEC, 8)] = "La Inmaculada Concepción"
2742        self[date(year, DEC, 25)] = "Navidad"
2743        if self.prov and self.prov in ['CAT', 'IBA']:
2744            self[date(year, DEC, 26)] = "San Esteban"
2745        # Provinces festive day
2746        if self.prov:
2747            if self.prov == 'AND':
2748                self[date(year, FEB, 28)] = "Día de Andalucia"
2749            elif self.prov == 'ARG':
2750                self[date(year, APR, 23)] = "Día de San Jorge"
2751            elif self.prov == 'AST':
2752                self[date(year, MAR, 8)] = "Día de Asturias"
2753            elif self.prov == 'CAN':
2754                self[date(year, FEB, 28)] = "Día de la Montaña"
2755            elif self.prov == 'CAM':
2756                self[date(year, FEB, 28)] = "Día de Castilla - La Mancha"
2757            elif self.prov == 'CAL':
2758                self[date(year, APR, 23)] = "Día de Castilla y Leon"
2759            elif self.prov == 'CAT':
2760                self[date(year, SEP, 11)] = "Día Nacional de Catalunya"
2761            elif self.prov == 'CVA':
2762                self[date(year, OCT, 9)] = "Día de la Comunidad Valenciana"
2763            elif self.prov == 'EXT':
2764                self[date(year, SEP, 8)] = "Día de Extremadura"
2765            elif self.prov == 'GAL':
2766                self[date(year, JUL, 25)] = "Día Nacional de Galicia"
2767            elif self.prov == 'IBA':
2768                self[date(year, MAR, 1)] = "Día de las Islas Baleares"
2769            elif self.prov == 'ICA':
2770                self[date(year, MAY, 30)] = "Día de Canarias"
2771            elif self.prov == 'MAD':
2772                self[date(year, MAY, 2)] = "Día de Comunidad De Madrid"
2773            elif self.prov == 'MUR':
2774                self[date(year, JUN, 9)] = "Día de la Región de Murcia"
2775            elif self.prov == 'NAV':
2776                self[date(year, SEP, 27)] = "Día de Navarra"
2777            elif self.prov == 'PVA':
2778                self[date(year, OCT, 25)] = "Día del Páis Vasco"
2779            elif self.prov == 'RIO':
2780                self[date(year, JUN, 9)] = "Día de La Rioja"
2781
2782
2783class ES(Spain):
2784    pass
2785
2786
2787class EuropeanCentralBank(HolidayBase):
2788    # https://en.wikipedia.org/wiki/TARGET2
2789    # http://www.ecb.europa.eu/press/pr/date/2000/html/pr001214_4.en.html
2790
2791    def __init__(self, **kwargs):
2792        self.country = 'EU'
2793        HolidayBase.__init__(self, **kwargs)
2794
2795    def _populate(self, year):
2796        self[date(year, JAN, 1)] = "New Year's Day"
2797        e = easter(year)
2798        self[e - rd(days=2)] = "Good Friday"
2799        self[e + rd(days=1)] = "Easter Monday"
2800        self[date(year, MAY, 1)] = "1 May (Labour Day)"
2801        self[date(year, DEC, 25)] = "Christmas Day"
2802        self[date(year, DEC, 26)] = "26 December"
2803
2804
2805class ECB(EuropeanCentralBank):
2806    pass
2807
2808
2809class TAR(EuropeanCentralBank):
2810    pass
2811
2812
2813class Czechia(HolidayBase):
2814    # https://en.wikipedia.org/wiki/Public_holidays_in_the_Czech_Republic
2815
2816    def __init__(self, **kwargs):
2817        self.country = 'CZ'
2818        HolidayBase.__init__(self, **kwargs)
2819
2820    def _populate(self, year):
2821        self[date(year, JAN, 1)] = "Den obnovy samostatného českého" \
2822                                   " státu" \
2823            if year >= 2000 else \
2824            "Nový rok"
2825
2826        e = easter(year)
2827        if year <= 1951 or year >= 2016:
2828            self[e - rd(days=2)] = "Velký pátek"
2829        self[e + rd(days=1)] = "Velikonoční pondělí"
2830
2831        if year >= 1951:
2832            self[date(year, MAY, 1)] = "Svátek práce"
2833        if year >= 1992:
2834            self[date(year, MAY, 8)] = "Den vítězství"
2835        elif year >= 1947:
2836            self[date(year, MAY, 9)] = "Den vítězství nad hitlerovským" \
2837                                       " fašismem"
2838        if year >= 1951:
2839            self[date(year, JUL, 5)] = "Den slovanských věrozvěstů " \
2840                "Cyrila a Metoděje"
2841            self[date(year, JUL, 6)] = "Den upálení mistra Jana Husa"
2842        if year >= 2000:
2843            self[date(year, SEP, 28)] = "Den české státnosti"
2844        if year >= 1951:
2845            self[date(year, OCT, 28)] = "Den vzniku samostatného " \
2846                "československého státu"
2847        if year >= 1990:
2848            self[date(year, NOV, 17)] = "Den boje za svobodu a demokracii"
2849
2850        if year >= 1990:
2851            self[date(year, DEC, 24)] = "Štědrý den"
2852        if year >= 1951:
2853            self[date(year, DEC, 25)] = "1. svátek vánoční"
2854            self[date(year, DEC, 26)] = "2. svátek vánoční"
2855
2856
2857class CZ(Czechia):
2858    pass
2859
2860
2861class Czech(Czechia):
2862    def __init__(self, **kwargs):
2863        warnings.warn("Czech is deprecated, use Czechia instead.",
2864                      DeprecationWarning)
2865        super(Czech, self).__init__(**kwargs)
2866
2867
2868class Slovakia(HolidayBase):
2869    # https://sk.wikipedia.org/wiki/Sviatok
2870    # https://www.slov-lex.sk/pravne-predpisy/SK/ZZ/1993/241/20181011.html
2871
2872    def __init__(self, **kwargs):
2873        self.country = 'SK'
2874        HolidayBase.__init__(self, **kwargs)
2875
2876    def _populate(self, year):
2877        self[date(year, JAN, 1)] = "Deň vzniku Slovenskej republiky"
2878        self[date(year, JAN, 6)] = "Zjavenie Pána (Traja králi a" \
2879                                   " vianočnýsviatok pravoslávnych" \
2880                                   " kresťanov)"
2881
2882        e = easter(year)
2883        self[e - rd(days=2)] = "Veľký piatok"
2884        self[e + rd(days=1)] = "Veľkonočný pondelok"
2885
2886        self[date(year, MAY, 1)] = "Sviatok práce"
2887
2888        if year >= 1997:
2889            self[date(year, MAY, 8)] = "Deň víťazstva nad fašizmom"
2890
2891        self[date(year, JUL, 5)] = "Sviatok svätého Cyrila a svätého Metoda"
2892
2893        self[date(year, AUG, 29)] = "Výročie Slovenského národného" \
2894                                    " povstania"
2895
2896        self[date(year, SEP, 1)] = "Deň Ústavy Slovenskej republiky"
2897
2898        self[date(year, SEP, 15)] = "Sedembolestná Panna Mária"
2899        if year == 2018:
2900            self[date(year, OCT, 30)] = "100. výročie prijatia" \
2901                " Deklarácie slovenského národa"
2902        self[date(year, NOV, 1)] = "Sviatok Všetkých svätých"
2903
2904        if year >= 2001:
2905            self[date(year, NOV, 17)] = "Deň boja za slobodu a demokraciu"
2906
2907        self[date(year, DEC, 24)] = "Štedrý deň"
2908
2909        self[date(year, DEC, 25)] = "Prvý sviatok vianočný"
2910
2911        self[date(year, DEC, 26)] = "Druhý sviatok vianočný"
2912
2913
2914class SK(Slovakia):
2915    pass
2916
2917
2918class Slovak(Slovakia):
2919    def __init__(self, **kwargs):
2920        warnings.warn("Slovak is deprecated, use Slovakia instead.",
2921                      DeprecationWarning)
2922        super(Slovak, self).__init__(**kwargs)
2923
2924
2925class Poland(HolidayBase):
2926    # https://pl.wikipedia.org/wiki/Dni_wolne_od_pracy_w_Polsce
2927
2928    def __init__(self, **kwargs):
2929        self.country = 'PL'
2930        HolidayBase.__init__(self, **kwargs)
2931
2932    def _populate(self, year):
2933        self[date(year, JAN, 1)] = 'Nowy Rok'
2934        if year >= 2011:
2935            self[date(year, JAN, 6)] = 'Święto Trzech Króli'
2936
2937        e = easter(year)
2938        self[e] = 'Niedziela Wielkanocna'
2939        self[e + rd(days=1)] = 'Poniedziałek Wielkanocny'
2940
2941        if year >= 1950:
2942            self[date(year, MAY, 1)] = 'Święto Państwowe'
2943        if year >= 1919:
2944            self[date(year, MAY, 3)] = 'Święto Narodowe Trzeciego Maja'
2945
2946        self[e + rd(days=49)] = 'Zielone Świątki'
2947        self[e + rd(days=60)] = 'Dzień Bożego Ciała'
2948
2949        self[date(year, AUG, 15)] = 'Wniebowzięcie Najświętszej Marii Panny'
2950
2951        self[date(year, NOV, 1)] = 'Uroczystość Wszystkich świętych'
2952        if (1937 <= year <= 1945) or year >= 1989:
2953            self[date(year, NOV, 11)] = 'Narodowe Święto Niepodległości'
2954
2955        self[date(year, DEC, 25)] = 'Boże Narodzenie (pierwszy dzień)'
2956        self[date(year, DEC, 26)] = 'Boże Narodzenie (drugi dzień)'
2957
2958
2959class Polish(Poland):
2960    def __init__(self, **kwargs):
2961        warnings.warn("Polish is deprecated, use Poland instead.",
2962                      DeprecationWarning)
2963        super(Polish, self).__init__(**kwargs)
2964
2965
2966class PL(Poland):
2967    pass
2968
2969
2970class Portugal(HolidayBase):
2971    # https://en.wikipedia.org/wiki/Public_holidays_in_Portugal
2972
2973    def __init__(self, **kwargs):
2974        self.country = 'PT'
2975        HolidayBase.__init__(self, **kwargs)
2976
2977    def _populate(self, year):
2978        self[date(year, JAN, 1)] = "Ano Novo"
2979
2980        e = easter(year)
2981
2982        # carnival is no longer a holiday, but some companies let workers off.
2983        # @todo recollect the years in which it was a public holiday
2984        # self[e - rd(days=47)] = "Carnaval"
2985        self[e - rd(days=2)] = "Sexta-feira Santa"
2986        self[e] = "Páscoa"
2987
2988        # Revoked holidays in 2013–2015
2989        if year < 2013 or year > 2015:
2990            self[e + rd(days=60)] = "Corpo de Deus"
2991            self[date(year, OCT, 5)] = "Implantação da República"
2992            self[date(year, NOV, 1)] = "Dia de Todos os Santos"
2993            self[date(year, DEC, 1)] = "Restauração da Independência"
2994
2995        self[date(year, 4, 25)] = "Dia da Liberdade"
2996        self[date(year, 5, 1)] = "Dia do Trabalhador"
2997        self[date(year, 6, 10)] = "Dia de Portugal"
2998        self[date(year, 8, 15)] = "Assunção de Nossa Senhora"
2999        self[date(year, DEC, 8)] = "Imaculada Conceição"
3000        self[date(year, DEC, 25)] = "Christmas Day"
3001
3002
3003class PT(Portugal):
3004    pass
3005
3006
3007class PortugalExt(Portugal):
3008    """
3009    Adds extended days that most people have as a bonus from their companies:
3010    - Carnival
3011    - the day before and after xmas
3012    - the day before the new year
3013    - Lisbon's city holiday
3014    """
3015
3016    def _populate(self, year):
3017        super(PortugalExt, self)._populate(year)
3018
3019        e = easter(year)
3020        self[e - rd(days=47)] = "Carnaval"
3021        self[date(year, DEC, 24)] = "Vespera de Natal"
3022        self[date(year, DEC, 26)] = "26 de Dezembro"
3023        self[date(year, DEC, 31)] = "Vespera de Ano novo"
3024        self[date(year, 6, 13)] = "Dia de Santo António"
3025
3026        # TODO add bridging days
3027        # - get Holidays that occur on Tuesday  and add Monday (-1 day)
3028        # - get Holidays that occur on Thursday and add Friday (+1 day)
3029
3030
3031class PTE(PortugalExt):
3032    pass
3033
3034
3035class Netherlands(HolidayBase):
3036    SUN = 6
3037
3038    def __init__(self, **kwargs):
3039        # http://www.iamsterdam.com/en/plan-your-trip/practical-info/public-holidays
3040        self.country = "NL"
3041        HolidayBase.__init__(self, **kwargs)
3042
3043    def _populate(self, year):
3044        # New years
3045        self[date(year, JAN, 1)] = "Nieuwjaarsdag"
3046
3047        easter_date = easter(year)
3048
3049        # Easter
3050        self[easter_date] = "Eerste paasdag"
3051
3052        # Second easter day
3053        self[easter_date + rd(days=1)] = "Tweede paasdag"
3054
3055        # Ascension day
3056        self[easter_date + rd(days=39)] = "Hemelvaart"
3057
3058        # Pentecost
3059        self[easter_date + rd(days=49)] = "Eerste Pinksterdag"
3060
3061        # Pentecost monday
3062        self[easter_date + rd(days=50)] = "Tweede Pinksterdag"
3063
3064        # First christmas
3065        self[date(year, DEC, 25)] = "Eerste Kerstdag"
3066
3067        # Second christmas
3068        self[date(year, DEC, 26)] = "Tweede Kerstdag"
3069
3070        # Liberation day
3071        if year >= 1945 and year % 5 == 0:
3072            self[date(year, MAY, 5)] = "Bevrijdingsdag"
3073
3074        # Kingsday
3075        if year >= 2014:
3076            kings_day = date(year, APR, 27)
3077            if kings_day.weekday() == self.SUN:
3078                kings_day = kings_day - rd(days=1)
3079
3080            self[kings_day] = "Koningsdag"
3081
3082        # Queen's day
3083        if 1891 <= year <= 2013:
3084            queens_day = date(year, APR, 30)
3085            if year <= 1948:
3086                queens_day = date(year, AUG, 31)
3087
3088            if queens_day.weekday() == self.SUN:
3089                if year < 1980:
3090                    queens_day = queens_day + rd(days=1)
3091                else:
3092                    queens_day = queens_day - rd(days=1)
3093
3094            self[queens_day] = "Koninginnedag"
3095
3096
3097class NL(Netherlands):
3098    pass
3099
3100
3101class Norway(HolidayBase):
3102    """
3103    Norwegian holidays.
3104    Note that holidays falling on a sunday is "lost",
3105    it will not be moved to another day to make up for the collision.
3106
3107    In Norway, ALL sundays are considered a holiday (https://snl.no/helligdag).
3108    Initialize this class with include_sundays=False
3109    to not include sundays as a holiday.
3110
3111    Primary sources:
3112    https://lovdata.no/dokument/NL/lov/1947-04-26-1
3113    https://no.wikipedia.org/wiki/Helligdager_i_Norge
3114    https://www.timeanddate.no/merkedag/norge/
3115    """
3116
3117    def __init__(self, include_sundays=True, **kwargs):
3118        """
3119
3120        :param include_sundays: Whether to consider sundays as a holiday
3121        (which they are in Norway)
3122        :param kwargs:
3123        """
3124        self.country = "NO"
3125        self.include_sundays = include_sundays
3126        HolidayBase.__init__(self, **kwargs)
3127
3128    def _populate(self, year):
3129        # Add all the sundays of the year before adding the "real" holidays
3130        if self.include_sundays:
3131            first_day_of_year = date(year, JAN, 1)
3132            first_sunday_of_year = \
3133                first_day_of_year + \
3134                rd(days=SUN - first_day_of_year.weekday())
3135            cur_date = first_sunday_of_year
3136
3137            while cur_date < date(year + 1, 1, 1):
3138                assert cur_date.weekday() == SUN
3139
3140                self[cur_date] = "Søndag"
3141                cur_date += rd(days=7)
3142
3143        # ========= Static holidays =========
3144        self[date(year, JAN, 1)] = "Første nyttårsdag"
3145
3146        # Source: https://lovdata.no/dokument/NL/lov/1947-04-26-1
3147        if year >= 1947:
3148            self[date(year, MAY, 1)] = "Arbeidernes dag"
3149            self[date(year, MAY, 17)] = "Grunnlovsdag"
3150
3151        # According to https://no.wikipedia.org/wiki/F%C3%B8rste_juledag,
3152        # these dates are only valid from year > 1700
3153        # Wikipedia has no source for the statement, so leaving this be for now
3154        self[date(year, DEC, 25)] = "Første juledag"
3155        self[date(year, DEC, 26)] = "Andre juledag"
3156
3157        # ========= Moving holidays =========
3158        # NOTE: These are probably subject to the same > 1700
3159        # restriction as the above dates. The only source I could find for how
3160        # long Easter has been celebrated in Norway was
3161        # https://www.hf.uio.no/ikos/tjenester/kunnskap/samlinger/norsk-folkeminnesamling/livs-og-arshoytider/paske.html
3162        # which says
3163        # "(...) has been celebrated for over 1000 years (...)" (in Norway)
3164        e = easter(year)
3165        maundy_thursday = e - rd(days=3)
3166        good_friday = e - rd(days=2)
3167        resurrection_sunday = e
3168        easter_monday = e + rd(days=1)
3169        ascension_thursday = e + rd(days=39)
3170        pentecost = e + rd(days=49)
3171        pentecost_day_two = e + rd(days=50)
3172
3173        assert maundy_thursday.weekday() == THU
3174        assert good_friday.weekday() == FRI
3175        assert resurrection_sunday.weekday() == SUN
3176        assert easter_monday.weekday() == MON
3177        assert ascension_thursday.weekday() == THU
3178        assert pentecost.weekday() == SUN
3179        assert pentecost_day_two.weekday() == MON
3180
3181        self[maundy_thursday] = "Skjærtorsdag"
3182        self[good_friday] = "Langfredag"
3183        self[resurrection_sunday] = "Første påskedag"
3184        self[easter_monday] = "Andre påskedag"
3185        self[ascension_thursday] = "Kristi himmelfartsdag"
3186        self[pentecost] = "Første pinsedag"
3187        self[pentecost_day_two] = "Andre pinsedag"
3188
3189
3190class NO(Norway):
3191    pass
3192
3193
3194class Italy(HolidayBase):
3195    PROVINCES = ['AN', 'AO', 'BA', 'BL', 'BO',
3196                 'BZ', 'BS', 'CB', 'CT', 'Cesena',
3197                 'CH', 'CS', 'KR', 'EN', 'FE', 'FI',
3198                 'FC', 'Forli', 'FR', 'GE', 'GO', 'IS',
3199                 'SP', 'LT', 'MN', 'MS', 'MI',
3200                 'MO', 'MB', 'NA', 'PD', 'PA',
3201                 'PR', 'PG', 'PE', 'PC', 'PI',
3202                 'PD', 'PT', 'RA', 'RE',
3203                 'RI', 'RN', 'RM', 'RO', 'SA',
3204                 'SR', 'TE', 'TO', 'TS', 'Pesaro', 'PU',
3205                 'Urbino', 'VE', 'VC', 'VI']
3206
3207    def __init__(self, **kwargs):
3208        self.country = 'IT'
3209        self.prov = kwargs.pop('prov', kwargs.pop('state', ''))
3210        HolidayBase.__init__(self, **kwargs)
3211
3212    def _populate(self, year):
3213        self[date(year, JAN, 1)] = "Capodanno"
3214        self[date(year, JAN, 6)] = "Epifania del Signore"
3215        self[easter(year)] = "Pasqua di Resurrezione"
3216        self[easter(year) + rd(weekday=MO)] = "Lunedì dell'Angelo"
3217        if year >= 1946:
3218            self[date(year, APR, 25)] = "Festa della Liberazione"
3219        self[date(year, MAY, 1)] = "Festa dei Lavoratori"
3220        if year >= 1948:
3221            self[date(year, JUN, 2)] = "Festa della Repubblica"
3222        self[date(year, AUG, 15)] = "Assunzione della Vergine"
3223        self[date(year, NOV, 1)] = "Tutti i Santi"
3224        self[date(year, DEC, 8)] = "Immacolata Concezione"
3225        self[date(year, DEC, 25)] = "Natale"
3226        self[date(year, DEC, 26)] = "Santo Stefano"
3227
3228        # Provinces holidays
3229        if self.prov:
3230            if self.prov == 'AN':
3231                self[date(year, MAY, 4)] = "San Ciriaco"
3232            elif self.prov == 'AO':
3233                self[date(year, SEP, 7)] = "San Grato"
3234            elif self.prov in ('BA'):
3235                self[date(year, DEC, 6)] = "San Nicola"
3236            elif self.prov == 'BL':
3237                self[date(year, NOV, 11)] = "San Martino"
3238            elif self.prov in ('BO'):
3239                self[date(year, OCT, 4)] = "San Petronio"
3240            elif self.prov == 'BZ':
3241                self[date(year, AUG, 15)] = "Maria Santissima Assunta"
3242            elif self.prov == 'BS':
3243                self[date(year, FEB, 15)] = "Santi Faustino e Giovita"
3244            elif self.prov == 'CB':
3245                self[date(year, APR, 23)] = "San Giorgio"
3246            elif self.prov == 'CT':
3247                self[date(year, FEB, 5)] = "Sant'Agata"
3248            elif self.prov in ('FC', 'Cesena'):
3249                self[date(year, JUN, 24)] = "San Giovanni Battista"
3250            if self.prov in ('FC', 'Forlì'):
3251                self[date(year, FEB, 4)] = "Madonna del Fuoco"
3252            elif self.prov == 'CH':
3253                self[date(year, MAY, 11)] = "San Giustino di Chieti"
3254            elif self.prov == 'CS':
3255                self[date(year, FEB, 12)] = "Madonna del Pilerio"
3256            elif self.prov == 'KR':
3257                self[date(year, OCT, 9)] = "San Dionigi"
3258            elif self.prov == 'EN':
3259                self[date(year, JUL, 2)] = "Madonna della Visitazione"
3260            elif self.prov == 'FE':
3261                self[date(year, APR, 23)] = "San Giorgio"
3262            elif self.prov == 'FI':
3263                self[date(year, JUN, 24)] = "San Giovanni Battista"
3264            elif self.prov == 'FR':
3265                self[date(year, JUN, 20)] = "San Silverio"
3266            elif self.prov == 'GE':
3267                self[date(year, JUN, 24)] = "San Giovanni Battista"
3268            elif self.prov == 'GO':
3269                self[date(year, MAR, 16)] = "Santi Ilario e Taziano"
3270            elif self.prov == 'IS':
3271                self[date(year, MAY, 19)] = "San Pietro Celestino"
3272            elif self.prov == 'SP':
3273                self[date(year, MAR, 19)] = "San Giuseppe"
3274            elif self.prov == 'LT':
3275                self[date(year, APR, 25)] = "San Marco evangelista"
3276            elif self.prov == 'ME':
3277                self[date(year, JUN, 3)] = "Madonna della Lettera"
3278            elif self.prov == 'MI':
3279                self[date(year, DEC, 7)] = "Sant'Ambrogio"
3280            elif self.prov == 'MN':
3281                self[date(year, MAR, 18)] = "Sant'Anselmo da Baggio"
3282            elif self.prov == 'MS':
3283                self[date(year, OCT, 4)] = "San Francesco d'Assisi"
3284            elif self.prov == 'MO':
3285                self[date(year, JAN, 31)] = "San Geminiano"
3286            elif self.prov == 'MB':
3287                self[date(year, JUN, 24)] = "San Giovanni Battista"
3288            elif self.prov == 'NA':
3289                self[date(year, SEP, 19)] = "San Gennaro"
3290            elif self.prov == 'PD':
3291                self[date(year, JUN, 13)] = "Sant'Antonio di Padova"
3292            elif self.prov == 'PA':
3293                self[date(year, JUL, 15)] = "San Giovanni"
3294            elif self.prov == 'PR':
3295                self[date(year, JAN, 13)] = "Sant'Ilario di Poitiers"
3296            elif self.prov == 'PG':
3297                self[date(year, JAN, 29)] = "Sant'Ercolano e San Lorenzo"
3298            elif self.prov == 'PC':
3299                self[date(year, JUL, 4)] = "Sant'Antonino di Piacenza"
3300            elif self.prov == 'RM':
3301                self[date(year, JUN, 29)] = "Santi Pietro e Paolo"
3302            elif self.prov == 'TO':
3303                self[date(year, JUN, 24)] = "San Giovanni Battista"
3304            elif self.prov == 'TS':
3305                self[date(year, NOV, 3)] = "San Giusto"
3306            elif self.prov == 'VI':
3307                self[date(year, APR, 25)] = "San Marco"
3308
3309        # TODO: add missing provinces' holidays:
3310        # 'Pisa', 'Pordenone', 'Potenza', 'Ravenna',
3311        # 'Reggio Emilia', 'Rieti', 'Rimini', 'Rovigo',
3312        # 'Salerno', 'Siracusa', 'Teramo', 'Torino', 'Urbino',
3313        # 'Venezia'
3314
3315
3316class IT(Italy):
3317    pass
3318
3319
3320class Sweden(HolidayBase):
3321    """
3322    Swedish holidays.
3323    Note that holidays falling on a sunday are "lost",
3324    it will not be moved to another day to make up for the collision.
3325    In Sweden, ALL sundays are considered a holiday
3326    (https://sv.wikipedia.org/wiki/Helgdagar_i_Sverige).
3327    Initialize this class with include_sundays=False
3328    to not include sundays as a holiday.
3329    Primary sources:
3330    https://sv.wikipedia.org/wiki/Helgdagar_i_Sverige and
3331    http://www.riksdagen.se/sv/dokument-lagar/dokument/svensk-forfattningssamling/lag-1989253-om-allmanna-helgdagar_sfs-1989-253
3332    """
3333
3334    def __init__(self, include_sundays=True, **kwargs):
3335        """
3336        :param include_sundays: Whether to consider sundays as a holiday
3337        (which they are in Sweden)
3338        :param kwargs:
3339        """
3340        self.country = "SE"
3341        self.include_sundays = include_sundays
3342        HolidayBase.__init__(self, **kwargs)
3343
3344    def _populate(self, year):
3345        # Add all the sundays of the year before adding the "real" holidays
3346        if self.include_sundays:
3347            first_day_of_year = date(year, JAN, 1)
3348            first_sunday_of_year = \
3349                first_day_of_year + \
3350                rd(days=SUN - first_day_of_year.weekday())
3351            cur_date = first_sunday_of_year
3352
3353            while cur_date < date(year + 1, 1, 1):
3354                assert cur_date.weekday() == SUN
3355
3356                self[cur_date] = "Söndag"
3357                cur_date += rd(days=7)
3358
3359        # ========= Static holidays =========
3360        self[date(year, JAN, 1)] = "Nyårsdagen"
3361
3362        self[date(year, JAN, 6)] = "Trettondedag jul"
3363
3364        # Source: https://sv.wikipedia.org/wiki/F%C3%B6rsta_maj
3365        if year >= 1939:
3366            self[date(year, MAY, 1)] = "Första maj"
3367
3368        # Source: https://sv.wikipedia.org/wiki/Sveriges_nationaldag
3369        if year >= 2005:
3370            self[date(year, JUN, 6)] = "Sveriges nationaldag"
3371
3372        self[date(year, DEC, 24)] = "Julafton"
3373        self[date(year, DEC, 25)] = "Juldagen"
3374        self[date(year, DEC, 26)] = "Annandag jul"
3375        self[date(year, DEC, 31)] = "Nyårsafton"
3376
3377        # ========= Moving holidays =========
3378        e = easter(year)
3379        maundy_thursday = e - rd(days=3)
3380        good_friday = e - rd(days=2)
3381        easter_saturday = e - rd(days=1)
3382        resurrection_sunday = e
3383        easter_monday = e + rd(days=1)
3384        ascension_thursday = e + rd(days=39)
3385        pentecost = e + rd(days=49)
3386        pentecost_day_two = e + rd(days=50)
3387
3388        assert maundy_thursday.weekday() == THU
3389        assert good_friday.weekday() == FRI
3390        assert easter_saturday.weekday() == SAT
3391        assert resurrection_sunday.weekday() == SUN
3392        assert easter_monday.weekday() == MON
3393        assert ascension_thursday.weekday() == THU
3394        assert pentecost.weekday() == SUN
3395        assert pentecost_day_two.weekday() == MON
3396
3397        self[good_friday] = "Långfredagen"
3398        self[resurrection_sunday] = "Påskdagen"
3399        self[easter_monday] = "Annandag påsk"
3400        self[ascension_thursday] = "Kristi himmelsfärdsdag"
3401        self[pentecost] = "Pingstdagen"
3402        if year <= 2004:
3403            self[pentecost_day_two] = "Annandag pingst"
3404
3405        # Midsummer evening. Friday between June 19th and June 25th
3406        self[date(year, JUN, 19) + rd(weekday=FR)] = "Midsommarafton"
3407
3408        # Midsummer day. Saturday between June 20th and June 26th
3409        if year >= 1953:
3410            self[date(year, JUN, 20) + rd(weekday=SA)] = "Midsommardagen"
3411        else:
3412            self[date(year, JUN, 24)] = "Midsommardagen"
3413            # All saints day. Friday between October 31th and November 6th
3414        self[date(year, OCT, 31) + rd(weekday=SA)] = "Alla helgons dag"
3415
3416        if year <= 1953:
3417            self[date(year, MAR, 25)] = "Jungfru Marie bebådelsedag"
3418
3419
3420class SE(Sweden):
3421    pass
3422
3423
3424class Japan(HolidayBase):
3425    # https://en.wikipedia.org/wiki/Public_holidays_in_Japan
3426
3427    def __init__(self, **kwargs):
3428        self.country = 'JP'
3429        HolidayBase.__init__(self, **kwargs)
3430
3431    def _populate(self, year):
3432        if year < 1949 or year > 2099:
3433            raise NotImplementedError
3434
3435        # New Year's Day
3436        self[date(year, JAN, 1)] = "元日"
3437
3438        # Coming of Age Day
3439        if year <= 1999:
3440            self[date(year, JAN, 15)] = "成人の日"
3441        else:
3442            self[date(year, JAN, 1) + rd(weekday=MO(+2))] = "成人の日"
3443
3444        # Foundation Day
3445        self[date(year, FEB, 11)] = "建国記念の日"
3446
3447        # Reiwa Emperor's Birthday
3448        if year >= 2020:
3449            self[date(year, FEB, 23)] = '天皇誕生日'
3450
3451        # Vernal Equinox Day
3452        self[self._vernal_equinox_day(year)] = "春分の日"
3453
3454        # Showa Emperor's Birthday, Greenery Day or Showa Day
3455        if year <= 1988:
3456            self[date(year, APR, 29)] = "天皇誕生日"
3457        elif year <= 2006:
3458            self[date(year, APR, 29)] = "みどりの日"
3459        else:
3460            self[date(year, APR, 29)] = "昭和の日"
3461
3462        # Constitution Memorial Day
3463        self[date(year, MAY, 3)] = "憲法記念日"
3464
3465        # Greenery Day
3466        if year >= 2007:
3467            self[date(year, MAY, 4)] = "みどりの日"
3468
3469        # Children's Day
3470        self[date(year, MAY, 5)] = "こどもの日"
3471
3472        # Marine Day
3473        if 1996 <= year <= 2002:
3474            self[date(year, JUL, 20)] = "海の日"
3475        elif year >= 2003:
3476            self[date(year, JUL, 1) + rd(weekday=MO(+3))] = "海の日"
3477
3478        # Mountain Day
3479        if year >= 2016:
3480            self[date(year, AUG, 11)] = "山の日"
3481
3482        # Respect for the Aged Day
3483        if 1966 <= year <= 2002:
3484            self[date(year, SEP, 15)] = "敬老の日"
3485        elif year >= 2003:
3486            self[date(year, SEP, 1) + rd(weekday=MO(+3))] = "敬老の日"
3487
3488        # Autumnal Equinox Day
3489        self[self._autumnal_equinox_day(year)] = "秋分の日"
3490
3491        # Health and Sports Day
3492        if 1966 <= year <= 1999:
3493            self[date(year, OCT, 10)] = "体育の日"
3494        elif year >= 2000:
3495            self[date(year, OCT, 1) + rd(weekday=MO(+2))] = "体育の日"
3496
3497        # Culture Day
3498        self[date(year, NOV, 3)] = "文化の日"
3499
3500        # Labour Thanksgiving Day
3501        self[date(year, NOV, 23)] = "勤労感謝の日"
3502
3503        # Heisei Emperor's Birthday
3504        if 1989 <= year <= 2018:
3505            self[date(year, DEC, 23)] = "天皇誕生日"
3506
3507        # Regarding the Emperor of Reiwa
3508        if year == 2019:
3509            # Enthronement Day
3510            self[date(year, MAY, 1)] = '天皇の即位の日'
3511            # Enthronement ceremony
3512            self[date(year, OCT, 22)] = '即位礼正殿の儀が行われる日'
3513
3514        # A weekday between national holidays becomes a holiday too (国民の休日)
3515        self._add_national_holidays(year)
3516
3517        # Substitute holidays
3518        self._add_substitute_holidays(year)
3519
3520    def _vernal_equinox_day(self, year):
3521        day = 20
3522        if year % 4 == 0:
3523            if year <= 1956:
3524                day = 21
3525            elif year >= 2092:
3526                day = 19
3527        elif year % 4 == 1:
3528            if year <= 1989:
3529                day = 21
3530        elif year % 4 == 2:
3531            if year <= 2022:
3532                day = 21
3533        elif year % 4 == 3:
3534            if year <= 2055:
3535                day = 21
3536        return date(year, MAR, day)
3537
3538    def _autumnal_equinox_day(self, year):
3539        day = 22
3540        if year % 4 == 0:
3541            if year <= 2008:
3542                day = 23
3543        elif year % 4 == 1:
3544            if year <= 2041:
3545                day = 23
3546        elif year % 4 == 2:
3547            if year <= 2074:
3548                day = 23
3549        elif year % 4 == 3:
3550            if year <= 1979:
3551                day = 24
3552            else:
3553                day = 23
3554        return date(year, SEP, day)
3555
3556    def _add_national_holidays(self, year):
3557        if year in (1993, 1999, 2004, 1988, 1994, 2005, 1989, 1995, 2000, 2006,
3558                    1990, 2001, 1991, 1996, 2002):
3559            self[date(year, MAY, 4)] = "国民の休日"
3560
3561        if year in (2032, 2049, 2060, 2077, 2088, 2094):
3562            self[date(year, SEP, 21)] = "国民の休日"
3563
3564        if year in (2009, 2015, 2026, 2037, 2043, 2054, 2065, 2071, 2099):
3565            self[date(year, SEP, 22)] = "国民の休日"
3566
3567        if year == 2019:
3568            self[date(year, APR, 30)] = '国民の休日'
3569            self[date(year, MAY, 2)] = '国民の休日'
3570
3571    def _add_substitute_holidays(self, year):
3572        table = (
3573            (1, 2, (1978, 1984, 1989, 1995, 2006, 2012, 2017, 2023, 2034, 2040,
3574                    2045)),
3575            (1, 16, (1978, 1984, 1989, 1995)),
3576            (2, 12, (1979, 1990, 1996, 2001, 2007, 2018, 2024, 2029, 2035,
3577                     2046)),
3578            (2, 24, (2020,)),
3579            (3, 21, (1988, 2005, 2016, 2033, 2044, 2050)),
3580            (3, 22, (1982, 1999, 2010, 2027)),
3581            (4, 30, (1973, 1979, 1984, 1990, 2001, 2007, 2012, 2018, 2029,
3582                     2035, 2040, 2046)),
3583            (5, 4, (1981, 1987, 1992, 1998)),
3584            (5, 6, (1985, 1991, 1996, 2002, 2013, 2019, 2024, 2030, 2041, 2047,
3585                    2008, 2014, 2025, 2031, 2036, 2042, 2009, 2015, 2020, 2026,
3586                    2037, 2043, 2048)),
3587            (7, 21, (1997,)),
3588            (8, 12, (2019, 2024, 2030, 2041, 2047)),
3589            (9, 16, (1974, 1985, 1991, 1996, 2002)),
3590            (9, 23, (2024,)),
3591            (9, 24, (1973, 1984, 1990, 2001, 2007, 2018, 2029, 2035, 2046)),
3592            (10, 11, (1976, 1982, 1993, 1999)),
3593            (11, 4, (1974, 1985, 1991, 1996, 2002, 2013, 2019, 2024, 2030,
3594                     2041, 2047)),
3595            (11, 24, (1975, 1980, 1986, 1997, 2003, 2008, 2014, 2025, 2031,
3596                      2036, 2042)),
3597            (12, 24, (1990, 2001, 2007, 2012, 2018)),
3598        )
3599        for holiday in table:
3600            month = holiday[0]
3601            day = holiday[1]
3602            years = holiday[2]
3603            if year in years:
3604                self[date(year, month, day)] = "振替休日"
3605
3606
3607class JP(Japan):
3608    pass
3609
3610
3611class France(HolidayBase):
3612    """Official French holidays.
3613
3614    Some provinces have specific holidays, only those are included in the
3615    PROVINCES, because these provinces have different administrative status,
3616    which makes it difficult to enumerate.
3617
3618    For religious holidays usually happening on Sundays (Easter, Pentecost),
3619    only the following Monday is considered a holiday.
3620
3621    Primary sources:
3622        https://fr.wikipedia.org/wiki/Fêtes_et_jours_fériés_en_France
3623        https://www.service-public.fr/particuliers/vosdroits/F2405
3624    """
3625
3626    PROVINCES = ['Métropole', 'Alsace-Moselle', 'Guadeloupe', 'Guyane',
3627                 'Martinique', 'Mayotte', 'Nouvelle-Calédonie', 'La Réunion',
3628                 'Polynésie Française', 'Saint-Barthélémy', 'Saint-Martin',
3629                 'Wallis-et-Futuna']
3630
3631    def __init__(self, **kwargs):
3632        self.country = 'FR'
3633        self.prov = kwargs.pop('prov', 'Métropole')
3634        HolidayBase.__init__(self, **kwargs)
3635
3636    def _populate(self, year):
3637        # Civil holidays
3638        if year > 1810:
3639            self[date(year, JAN, 1)] = "Jour de l'an"
3640
3641        if year > 1919:
3642            name = 'Fête du Travail'
3643            if year <= 1948:
3644                name += ' et de la Concorde sociale'
3645            self[date(year, MAY, 1)] = name
3646
3647        if (1953 <= year <= 1959) or year > 1981:
3648            self[date(year, MAY, 8)] = 'Armistice 1945'
3649
3650        if year >= 1880:
3651            self[date(year, JUL, 14)] = 'Fête nationale'
3652
3653        if year >= 1918:
3654            self[date(year, NOV, 11)] = 'Armistice 1918'
3655
3656        # Religious holidays
3657        if self.prov in ['Alsace-Moselle', 'Guadeloupe', 'Guyane',
3658                         'Martinique', 'Polynésie Française']:
3659            self[easter(year) - rd(days=2)] = 'Vendredi saint'
3660
3661        if self.prov == 'Alsace-Moselle':
3662            self[date(year, DEC, 26)] = 'Deuxième jour de Noël'
3663
3664        if year >= 1886:
3665            self[easter(year) + rd(days=1)] = 'Lundi de Pâques'
3666            self[easter(year) + rd(days=50)] = 'Lundi de Pentecôte'
3667
3668        if year >= 1802:
3669            self[easter(year) + rd(days=39)] = 'Ascension'
3670            self[date(year, AUG, 15)] = 'Assomption'
3671            self[date(year, NOV, 1)] = 'Toussaint'
3672
3673            name = 'Noël'
3674            if self.prov == 'Alsace-Moselle':
3675                name = 'Premier jour de ' + name
3676            self[date(year, DEC, 25)] = name
3677
3678        # Non-metropolitan holidays (starting dates missing)
3679        if self.prov == 'Mayotte':
3680            self[date(year, APR, 27)] = "Abolition de l'esclavage"
3681
3682        if self.prov == 'Wallis-et-Futuna':
3683            self[date(year, APR, 28)] = 'Saint Pierre Chanel'
3684
3685        if self.prov == 'Martinique':
3686            self[date(year, MAY, 22)] = "Abolition de l'esclavage"
3687
3688        if self.prov in ['Guadeloupe', 'Saint-Martin']:
3689            self[date(year, MAY, 27)] = "Abolition de l'esclavage"
3690
3691        if self.prov == 'Guyane':
3692            self[date(year, JUN, 10)] = "Abolition de l'esclavage"
3693
3694        if self.prov == 'Polynésie Française':
3695            self[date(year, JUN, 29)] = "Fête de l'autonomie"
3696
3697        if self.prov in ['Guadeloupe', 'Martinique']:
3698            self[date(year, JUL, 21)] = 'Fête Victor Schoelcher'
3699
3700        if self.prov == 'Wallis-et-Futuna':
3701            self[date(year, JUL, 29)] = 'Fête du Territoire'
3702
3703        if self.prov == 'Nouvelle-Calédonie':
3704            self[date(year, SEP, 24)] = 'Fête de la Citoyenneté'
3705
3706        if self.prov == 'Saint-Barthélémy':
3707            self[date(year, OCT, 9)] = "Abolition de l'esclavage"
3708
3709        if self.prov == 'La Réunion' and year >= 1981:
3710            self[date(year, DEC, 20)] = "Abolition de l'esclavage"
3711
3712
3713# FR already exists (Friday), we don't want to mess it up
3714class FRA(France):
3715    pass
3716
3717
3718class Belgium(HolidayBase):
3719    """
3720    https://www.belgium.be/nl/over_belgie/land/belgie_in_een_notendop/feestdagen
3721    https://nl.wikipedia.org/wiki/Feestdagen_in_Belgi%C3%AB
3722    """
3723
3724    def __init__(self, **kwargs):
3725        self.country = "BE"
3726        HolidayBase.__init__(self, **kwargs)
3727
3728    def _populate(self, year):
3729        # New years
3730        self[date(year, JAN, 1)] = "Nieuwjaarsdag"
3731
3732        easter_date = easter(year)
3733
3734        # Easter
3735        self[easter_date] = "Pasen"
3736
3737        # Second easter day
3738        self[easter_date + rd(days=1)] = "Paasmaandag"
3739
3740        # Ascension day
3741        self[easter_date + rd(days=39)] = "O.L.H. Hemelvaart"
3742
3743        # Pentecost
3744        self[easter_date + rd(days=49)] = "Pinksteren"
3745
3746        # Pentecost monday
3747        self[easter_date + rd(days=50)] = "Pinkstermaandag"
3748
3749        # International Workers' Day
3750        self[date(year, MAY, 1)] = "Dag van de Arbeid"
3751
3752        # Belgian National Day
3753        self[date(year, JUL, 21)] = "Nationale feestdag"
3754
3755        # Assumption of Mary
3756        self[date(year, AUG, 15)] = "O.L.V. Hemelvaart"
3757
3758        # All Saints' Day
3759        self[date(year, NOV, 1)] = "Allerheiligen"
3760
3761        # Armistice Day
3762        self[date(year, NOV, 11)] = "Wapenstilstand"
3763
3764        # First christmas
3765        self[date(year, DEC, 25)] = "Kerstmis"
3766
3767
3768class BE(Belgium):
3769    pass
3770
3771
3772class SouthAfrica(HolidayBase):
3773    def __init__(self, **kwargs):
3774        # http://www.gov.za/about-sa/public-holidays
3775        # https://en.wikipedia.org/wiki/Public_holidays_in_South_Africa
3776        self.country = "ZA"
3777        HolidayBase.__init__(self, **kwargs)
3778
3779    def _populate(self, year):
3780        # Observed since 1910, with a few name changes
3781        if year > 1909:
3782            self[date(year, 1, 1)] = "New Year's Day"
3783
3784            e = easter(year)
3785            good_friday = e - rd(days=2)
3786            easter_monday = e + rd(days=1)
3787            self[good_friday] = "Good Friday"
3788            if year > 1979:
3789                self[easter_monday] = "Family Day"
3790            else:
3791                self[easter_monday] = "Easter Monday"
3792
3793            if 1909 < year < 1952:
3794                dec_16_name = "Dingaan's Day"
3795            elif 1951 < year < 1980:
3796                dec_16_name = "Day of the Covenant"
3797            elif 1979 < year < 1995:
3798                dec_16_name = "Day of the Vow"
3799            else:
3800                dec_16_name = "Day of Reconciliation"
3801            self[date(year, DEC, 16)] = dec_16_name
3802
3803            self[date(year, DEC, 25)] = "Christmas Day"
3804
3805            if year > 1979:
3806                dec_26_name = "Day of Goodwill"
3807            else:
3808                dec_26_name = "Boxing Day"
3809            self[date(year, 12, 26)] = dec_26_name
3810
3811        # Observed since 1995/1/1
3812        if year > 1994:
3813            self[date(year, MAR, 21)] = "Human Rights Day"
3814            self[date(year, APR, 27)] = "Freedom Day"
3815            self[date(year, MAY, 1)] = "Workers' Day"
3816            self[date(year, JUN, 16)] = "Youth Day"
3817            self[date(year, AUG, 9)] = "National Women's Day"
3818            self[date(year, SEP, 24)] = "Heritage Day"
3819
3820        # Once-off public holidays
3821        national_election = "National and provincial government elections"
3822        y2k = "Y2K changeover"
3823        local_election = "Local government elections"
3824        presidential = "By presidential decree"
3825        if year == 1999:
3826            self[date(1999, JUN, 2)] = national_election
3827            self[date(1999, DEC, 31)] = y2k
3828        if year == 2000:
3829            self[date(2000, JAN, 2)] = y2k
3830        if year == 2004:
3831            self[date(2004, APR, 14)] = national_election
3832        if year == 2006:
3833            self[date(2006, MAR, 1)] = local_election
3834        if year == 2008:
3835            self[date(2008, MAY, 2)] = presidential
3836        if year == 2009:
3837            self[date(2009, APR, 22)] = national_election
3838        if year == 2011:
3839            self[date(2011, MAY, 18)] = local_election
3840            self[date(2011, DEC, 27)] = presidential
3841        if year == 2014:
3842            self[date(2014, MAY, 7)] = national_election
3843        if year == 2016:
3844            self[date(2016, AUG, 3)] = local_election
3845        if year == 2019:
3846            self[date(2019, MAY, 8)] = national_election
3847
3848        # As of 1995/1/1, whenever a public holiday falls on a Sunday,
3849        # it rolls over to the following Monday
3850        for k, v in list(self.items()):
3851            if self.observed and year > 1994 and k.weekday() == SUN:
3852                self[k + rd(days=1)] = v + " (Observed)"
3853
3854        # Historic public holidays no longer observed
3855        if 1951 < year < 1974:
3856            self[date(year, APR, 6)] = "Van Riebeeck's Day"
3857        elif 1979 < year < 1995:
3858            self[date(year, APR, 6)] = "Founder's Day"
3859
3860        if 1986 < year < 1990:
3861            historic_workers_day = datetime(year, MAY, 1)
3862            # observed on first Friday in May
3863            while historic_workers_day.weekday() != FRI:
3864                historic_workers_day += rd(days=1)
3865
3866            self[historic_workers_day] = "Workers' Day"
3867
3868        if 1909 < year < 1994:
3869            ascension_day = e + rd(days=40)
3870            self[ascension_day] = "Ascension Day"
3871
3872        if 1909 < year < 1952:
3873            self[date(year, MAY, 24)] = "Empire Day"
3874
3875        if 1909 < year < 1961:
3876            self[date(year, MAY, 31)] = "Union Day"
3877        elif 1960 < year < 1994:
3878            self[date(year, MAY, 31)] = "Republic Day"
3879
3880        if 1951 < year < 1961:
3881            queens_birthday = datetime(year, JUN, 7)
3882            # observed on second Monday in June
3883            while queens_birthday.weekday() != 0:
3884                queens_birthday += rd(days=1)
3885
3886            self[queens_birthday] = "Queen's Birthday"
3887
3888        if 1960 < year < 1974:
3889            self[date(year, JUL, 10)] = "Family Day"
3890
3891        if 1909 < year < 1952:
3892            kings_birthday = datetime(year, AUG, 1)
3893            # observed on first Monday in August
3894            while kings_birthday.weekday() != 0:
3895                kings_birthday += rd(days=1)
3896
3897            self[kings_birthday] = "King's Birthday"
3898
3899        if 1951 < year < 1980:
3900            settlers_day = datetime(year, SEP, 1)
3901            while settlers_day.weekday() != 0:
3902                settlers_day += rd(days=1)
3903
3904            self[settlers_day] = "Settlers' Day"
3905
3906        if 1951 < year < 1994:
3907            self[date(year, OCT, 10)] = "Kruger Day"
3908
3909
3910class ZA(SouthAfrica):
3911    pass
3912
3913
3914class Slovenia(HolidayBase):
3915    """
3916    Contains all work-free public holidays in Slovenia.
3917    No holidays are returned before year 1991 when Slovenia became independent
3918    country. Before that Slovenia was part of Socialist federal republic of
3919    Yugoslavia.
3920
3921    List of holidays (including those that are not work-free:
3922    https://en.wikipedia.org/wiki/Public_holidays_in_Slovenia
3923    """
3924
3925    def __init__(self, **kwargs):
3926        self.country = 'SI'
3927        HolidayBase.__init__(self, **kwargs)
3928
3929    def _populate(self, year):
3930        if year <= 1990:
3931            return
3932
3933        if year > 1991:
3934            self[date(year, JAN, 1)] = "novo leto"
3935
3936            # Between 2012 and 2017 2nd January was not public holiday,
3937            # or at least not work-free day
3938            if year < 2013 or year > 2016:
3939                self[date(year, JAN, 2)] = "novo leto"
3940
3941            # Prešeren's day, slovenian cultural holiday
3942            self[date(year, FEB, 8)] = "Prešernov dan"
3943
3944            # Easter monday is the only easter related work-free day
3945            easter_day = easter(year)
3946            self[easter_day + rd(days=1)] = "Velikonočni ponedeljek"
3947
3948            # Day of uprising against occupation
3949            self[date(year, APR, 27)] = "dan upora proti okupatorju"
3950
3951            # Labour day, two days of it!
3952            self[date(year, MAY, 1)] = "praznik dela"
3953            self[date(year, MAY, 2)] = "praznik dela"
3954
3955            # Statehood day
3956            self[date(year, JUN, 25)] = "dan državnosti"
3957
3958            # Assumption day
3959            self[date(year, AUG, 15)] = "Marijino vnebovzetje"
3960
3961            # Reformation day
3962            self[date(year, OCT, 31)] = "dan reformacije"
3963
3964            # Remembrance day
3965            self[date(year, NOV, 1)] = "dan spomina na mrtve"
3966
3967            # Christmas
3968            self[date(year, DEC, 25)] = "Božič"
3969
3970            # Day of independence and unity
3971            self[date(year, DEC, 26)] = "dan samostojnosti in enotnosti"
3972
3973
3974class SI(Slovenia):
3975    pass
3976
3977
3978class Finland(HolidayBase):
3979    # https://en.wikipedia.org/wiki/Public_holidays_in_Finland
3980
3981    def __init__(self, **kwargs):
3982        self.country = "FI"
3983        HolidayBase.__init__(self, **kwargs)
3984
3985    def _populate(self, year):
3986        e = easter(year)
3987
3988        self[date(year, JAN, 1)] = "Uudenvuodenpäivä"
3989        self[date(year, JAN, 6)] = "Loppiainen"
3990        self[e - rd(days=2)] = "Pitkäperjantai"
3991        self[e] = "Pääsiäispäivä"
3992        self[e + rd(days=1)] = "2. pääsiäispäivä"
3993        self[date(year, MAY, 1)] = "Vappu"
3994        self[e + rd(days=39)] = "Helatorstai"
3995        self[e + rd(days=49)] = "Helluntaipäivä"
3996        self[date(year, JUN, 20) + rd(weekday=SA)] = "Juhannuspäivä"
3997        self[date(year, OCT, 31) + rd(weekday=SA)] = "Pyhäinpäivä"
3998        self[date(year, DEC, 6)] = "Itsenäisyyspäivä"
3999        self[date(year, DEC, 25)] = "Joulupäivä"
4000        self[date(year, DEC, 26)] = "Tapaninpäivä"
4001
4002        # Juhannusaatto (Midsummer Eve) and Jouluaatto (Christmas Eve) are not
4003        # official holidays, but are de facto.
4004        self[date(year, JUN, 19) + rd(weekday=FR)] = "Juhannusaatto"
4005        self[date(year, DEC, 24)] = "Jouluaatto"
4006
4007
4008class FI(Finland):
4009    pass
4010
4011
4012class Switzerland(HolidayBase):
4013    PROVINCES = ['AG', 'AR', 'AI', 'BL', 'BS', 'BE', 'FR', 'GE', 'GL',
4014                 'GR', 'JU', 'LU', 'NE', 'NW', 'OW', 'SG', 'SH', 'SZ',
4015                 'SO', 'TG', 'TI', 'UR', 'VD', 'VS', 'ZG', 'ZH']
4016
4017    def __init__(self, **kwargs):
4018        self.country = 'CH'
4019        HolidayBase.__init__(self, **kwargs)
4020
4021    def _populate(self, year):
4022        # public holidays
4023        self[date(year, JAN, 1)] = 'Neujahrestag'
4024
4025        if self.prov in ('AG', 'BE', 'FR', 'GE', 'GL', 'GR', 'JU', 'LU',
4026                         'NE', 'OW', 'SH', 'SO', 'TG', 'VD', 'ZG', 'ZH'):
4027            self[date(year, JAN, 2)] = 'Berchtoldstag'
4028
4029        if self.prov in ('SZ', 'TI', 'UR'):
4030            self[date(year, JAN, 6)] = 'Heilige Drei Könige'
4031
4032        if self.prov == 'NE':
4033            self[date(year, MAR, 1)] = 'Jahrestag der Ausrufung der Republik'
4034
4035        if self.prov in ('NW', 'SZ', 'TI', 'UR', 'VS'):
4036            self[date(year, MAR, 19)] = 'Josefstag'
4037
4038        # Näfelser Fahrt (first Thursday in April but not in Holy Week)
4039        if self.prov == 'GL' and year >= 1835:
4040            if ((date(year, APR, 1) + rd(weekday=FR)) !=
4041                    (easter(year) - rd(days=2))):
4042                self[date(year, APR, 1) + rd(weekday=TH)] = 'Näfelser Fahrt'
4043            else:
4044                self[date(year, APR, 8) + rd(weekday=TH)] = 'Näfelser Fahrt'
4045
4046        # it's a Holiday on a Sunday
4047        self[easter(year)] = 'Ostern'
4048
4049        # VS don't have easter
4050        if self.prov != 'VS':
4051            self[easter(year) - rd(days=2)] = 'Karfreitag'
4052            self[easter(year) + rd(weekday=MO)] = 'Ostermontag'
4053
4054        if self.prov in ('BL', 'BS', 'JU', 'NE', 'SH', 'SO', 'TG', 'TI',
4055                         'ZH'):
4056            self[date(year, MAY, 1)] = 'Tag der Arbeit'
4057
4058        self[easter(year) + rd(days=39)] = 'Auffahrt'
4059
4060        # it's a Holiday on a Sunday
4061        self[easter(year) + rd(days=49)] = 'Pfingsten'
4062
4063        self[easter(year) + rd(days=50)] = 'Pfingstmontag'
4064
4065        if self.prov in ('AI', 'JU', 'LU', 'NW', 'OW', 'SZ', 'TI', 'UR',
4066                         'VS', 'ZG'):
4067            self[easter(year) + rd(days=60)] = 'Fronleichnam'
4068
4069        if self.prov == 'JU':
4070            self[date(year, JUN, 23)] = 'Fest der Unabhängigkeit'
4071
4072        if self.prov == 'TI':
4073            self[date(year, JUN, 29)] = 'Peter und Paul'
4074
4075        if year >= 1291:
4076            self[date(year, AUG, 1)] = 'Nationalfeiertag'
4077
4078        if self.prov in ('AI', 'JU', 'LU', 'NW', 'OW', 'SZ', 'TI', 'UR',
4079                         'VS', 'ZG'):
4080            self[date(year, AUG, 15)] = 'Mariä Himmelfahrt'
4081
4082        if self.prov == 'VD':
4083            # Monday after the third Sunday of September
4084            dt = date(year, SEP, 1) + rd(weekday=SU(+3)) + rd(weekday=MO)
4085            self[dt] = 'Lundi du Jeûne'
4086
4087        if self.prov == 'OW':
4088            self[date(year, SEP, 25)] = 'Bruder Klaus'
4089
4090        if self.prov in ('AI', 'GL', 'JU', 'LU', 'NW', 'OW', 'SG', 'SZ',
4091                         'TI', 'UR', 'VS', 'ZG'):
4092            self[date(year, NOV, 1)] = 'Allerheiligen'
4093
4094        if self.prov in ('AI', 'LU', 'NW', 'OW', 'SZ', 'TI', 'UR', 'VS',
4095                         'ZG'):
4096            self[date(year, DEC, 8)] = 'Mariä Empfängnis'
4097
4098        if self.prov == 'GE':
4099            self[date(year, DEC, 12)] = 'Escalade de Genève'
4100
4101        self[date(year, DEC, 25)] = 'Weihnachten'
4102
4103        if self.prov in ('AG', 'AR', 'AI', 'BL', 'BS', 'BE', 'FR', 'GL',
4104                         'GR', 'LU', 'NE', 'NW', 'OW', 'SG', 'SH', 'SZ',
4105                         'SO', 'TG', 'TI', 'UR', 'ZG', 'ZH'):
4106            self[date(year, DEC, 26)] = 'Stephanstag'
4107
4108        if self.prov == 'GE':
4109            self[date(year, DEC, 31)] = 'Wiederherstellung der Republik'
4110
4111
4112class CH(Switzerland):
4113    pass
4114
4115
4116class Honduras(HolidayBase):
4117    # https://www.timeanddate.com/holidays/honduras/
4118
4119    def __init__(self, **kwargs):
4120        self.country = "HND"
4121        HolidayBase.__init__(self, **kwargs)
4122
4123    def _populate(self, year):
4124        # New Year's Day
4125        if self.observed and date(year, JAN, 1):
4126            self[date(year, JAN, 1)] = "Año Nuevo [New Year's Day]"
4127
4128        # The Three Wise Men Day
4129        if self.observed and date(year, JAN, 6):
4130            name = "Día de los Reyes Magos [The Three Wise Men Day] (Observed)"
4131            self[date(year, JAN, 6)] = name
4132
4133        # The Three Wise Men Day
4134        if self.observed and date(year, FEB, 3):
4135            name = "Día de la virgen de Suyapa [Our Lady of Suyapa] (Observed)"
4136            self[date(year, FEB, 3)] = name
4137
4138        # The Father's Day
4139        if self.observed and date(year, MAR, 19):
4140            name = "Día del Padre [Father's Day] (Observed)"
4141            self[date(year, MAR, 19)] = name
4142
4143        # Maundy Thursday
4144        self[easter(year) + rd(weekday=TH(-1))
4145             ] = "Jueves Santo [Maundy Thursday]"
4146
4147        # Good Friday
4148        self[easter(year) + rd(weekday=FR(-1))
4149             ] = "Viernes Santo [Good Friday]"
4150
4151        # Holy Saturday
4152        self[easter(year) + rd(weekday=SA(-1))
4153             ] = "Sábado de Gloria [Holy Saturday]"
4154
4155        # Easter Sunday
4156        self[easter(year) + rd(weekday=SU(-1))
4157             ] = "Domingo de Resurrección [Easter Sunday]"
4158
4159        # America Day
4160        if self.observed and date(year, APR, 14):
4161            self[date(year, APR, 14)] = "Día de las Américas [America Day]"
4162
4163        # Labor Day
4164        if self.observed and date(year, MAY, 1):
4165            self[date(year, MAY, 1)] = "Día del Trabajo [Labour Day]"
4166
4167        # Mother's Day
4168        may_first = date(int(year), 5, 1)
4169        weekday_seq = may_first.weekday()
4170        mom_day = (14 - weekday_seq)
4171        if self.observed and date(year, MAY, mom_day):
4172            str_day = "Día de la madre [Mother's Day] (Observed)"
4173            self[date(year, MAY, mom_day)] = str_day
4174
4175        # Children's Day
4176        if self.observed and date(year, SEP, 10):
4177            name = "Día del niño [Children day] (Observed)"
4178            self[date(year, SEP, 10)] = name
4179
4180        # Independence Day
4181        if self.observed and date(year, SEP, 15):
4182            name = "Día de la Independencia [Independence Day]"
4183            self[date(year, SEP, 15)] = name
4184
4185        # Teacher's Day
4186        if self.observed and date(year, SEP, 17):
4187            name = "Día del Maestro [Teacher's day] (Observed)"
4188            self[date(year, SEP, 17)] = name
4189
4190        # October Holidays are joined on 3 days starting at October 3 to 6.
4191        # Some companies work medium day and take the rest on saturday.
4192        # This holiday is variant and some companies work normally.
4193        # If start day is weekend is ignored.
4194        # The main objective of this is to increase the tourism.
4195
4196        # https://www.hondurastips.hn/2017/09/20/de-donde-nace-el-feriado-morazanico/
4197
4198        if year <= 2014:
4199            # Morazan's Day
4200            if self.observed and date(year, OCT, 3):
4201                self[date(year, OCT, 3)] = "Día de Morazán [Morazan's Day]"
4202
4203            # Columbus Day
4204            if self.observed and date(year, OCT, 12):
4205                self[date(year, OCT, 12)] = "Día de la Raza [Columbus Day]"
4206
4207            # Amy Day
4208            if self.observed and date(year, OCT, 21):
4209                str_day = "Día de las Fuerzas Armadas [Army Day]"
4210                self[date(year, OCT, 21)] = str_day
4211        else:
4212            # Morazan Weekend
4213            if self.observed and date(year, OCT, 3):
4214                name = "Semana Morazánica [Morazan Weekend]"
4215                self[date(year, OCT, 3)] = name
4216
4217            # Morazan Weekend
4218            if self.observed and date(year, OCT, 4):
4219                name = "Semana Morazánica [Morazan Weekend]"
4220                self[date(year, OCT, 4)] = name
4221
4222            # Morazan Weekend
4223            if self.observed and date(year, OCT, 5):
4224                name = "Semana Morazánica [Morazan Weekend]"
4225                self[date(year, OCT, 5)] = name
4226
4227        # Christmas
4228        self[date(year, DEC, 25)] = "Navidad [Christmas]"
4229
4230
4231class HND(Honduras):
4232    pass
4233
4234
4235class Hungary(HolidayBase):
4236    # https://en.wikipedia.org/wiki/Public_holidays_in_Hungary
4237    # observed days off work around national holidays in the last 10 years:
4238    # https://www.munkaugyiforum.hu/munkaugyi-segedanyagok/
4239    #     2018-evi-munkaszuneti-napok-koruli-munkarend-9-2017-ngm-rendelet
4240    # codification dates:
4241    # - https://hvg.hu/gazdasag/
4242    #      20170307_Megszavaztak_munkaszuneti_nap_lett_a_nagypentek
4243    # - https://www.tankonyvtar.hu/hu/tartalom/historia/
4244    #      92-10/ch01.html#id496839
4245
4246    def __init__(self, **kwargs):
4247        self.country = "HU"
4248        HolidayBase.__init__(self, **kwargs)
4249
4250    def _populate(self, year):
4251        # New years
4252        self._add_with_observed_day_off(date(year, JAN, 1), "Újév", since=2014)
4253
4254        # National Day
4255        if 1945 <= year <= 1950 or 1989 <= year:
4256            self._add_with_observed_day_off(
4257                date(year, MAR, 15), "Nemzeti ünnep")
4258
4259        # Soviet era
4260        if 1950 <= year <= 1989:
4261            # Proclamation of Soviet socialist governing system
4262            self[date(year, MAR, 21)] = \
4263                "A Tanácsköztársaság kikiáltásának ünnepe"
4264            # Liberation Day
4265            self[date(year, APR, 4)] = "A felszabadulás ünnepe"
4266            # Memorial day of The Great October Soviet Socialist Revolution
4267            if year not in (1956, 1989):
4268                self[date(year, NOV, 7)] = \
4269                    "A nagy októberi szocialista forradalom ünnepe"
4270
4271        easter_date = easter(year)
4272
4273        # Good Friday
4274        if 2017 <= year:
4275            self[easter_date + rd(weekday=FR(-1))] = "Nagypéntek"
4276
4277        # Easter
4278        self[easter_date] = "Húsvét"
4279
4280        # Second easter day
4281        if 1955 != year:
4282            self[easter_date + rd(days=1)] = "Húsvét Hétfő"
4283
4284        # Pentecost
4285        self[easter_date + rd(days=49)] = "Pünkösd"
4286
4287        # Pentecost monday
4288        if year <= 1952 or 1992 <= year:
4289            self[easter_date + rd(days=50)] = "Pünkösdhétfő"
4290
4291        # International Workers' Day
4292        if 1946 <= year:
4293            self._add_with_observed_day_off(
4294                date(year, MAY, 1), "A Munka ünnepe")
4295        if 1950 <= year <= 1953:
4296            self[date(year, MAY, 2)] = "A Munka ünnepe"
4297
4298        # State Foundation Day (1771-????, 1891-)
4299        if 1950 <= year < 1990:
4300            self[date(year, AUG, 20)] = "A kenyér ünnepe"
4301        else:
4302            self._add_with_observed_day_off(
4303                date(year, AUG, 20), "Az államalapítás ünnepe")
4304
4305        # National Day
4306        if 1991 <= year:
4307            self._add_with_observed_day_off(
4308                date(year, OCT, 23), "Nemzeti ünnep")
4309
4310        # All Saints' Day
4311        if 1999 <= year:
4312            self._add_with_observed_day_off(
4313                date(year, NOV, 1), "Mindenszentek")
4314
4315        # Christmas Eve is not endorsed officially
4316        # but nowadays it is usually a day off work
4317        if self.observed and 2010 <= year \
4318                and date(year, DEC, 24).weekday() not in WEEKEND:
4319            self[date(year, DEC, 24)] = "Szenteste"
4320
4321        # First christmas
4322        self[date(year, DEC, 25)] = "Karácsony"
4323
4324        # Second christmas
4325        if 1955 != year:
4326            self._add_with_observed_day_off(
4327                date(year, DEC, 26), "Karácsony másnapja", since=2013,
4328                before=False, after=True)
4329
4330        # New Year's Eve
4331        if self.observed and 2014 <= year \
4332                and date(year, DEC, 31).weekday() == MON:
4333            self[date(year, DEC, 31)] = "Szilveszter"
4334
4335    def _add_with_observed_day_off(self, day, desc, since=2010,
4336                                   before=True, after=True):
4337        # Swapped days off were in place earlier but
4338        # I haven't found official record yet.
4339        self[day] = desc
4340        # TODO: should it be a separate flag?
4341        if self.observed and since <= day.year:
4342            if day.weekday() == TUE and before:
4343                self[day - rd(days=1)] = desc + " előtti pihenőnap"
4344            elif day.weekday() == THU and after:
4345                self[day + rd(days=1)] = desc + " utáni pihenőnap"
4346
4347
4348class HU(Hungary):
4349    pass
4350
4351
4352class India(HolidayBase):
4353    # https://en.wikipedia.org/wiki/Public_holidays_in_India
4354    # https://www.calendarlabs.com/holidays/india/
4355    # https://slusi.dacnet.nic.in/watershedatlas/list_of_state_abbreviation.htm
4356
4357    PROVINCES = ['AS', 'CG', 'SK', 'KA', 'GJ', 'BR', 'RJ', 'OD',
4358                 'TN', 'AP', 'WB', 'KL', 'HR', 'MH', 'MP', 'UP', 'UK', 'TS']
4359
4360    def __init__(self, **kwargs):
4361        self.country = "IND"
4362        HolidayBase.__init__(self, **kwargs)
4363
4364    def _populate(self, year):
4365        # Pongal/ Makar Sankranti
4366        self[date(year, JAN, 14)] = "Makar Sankranti / Pongal"
4367
4368        if year >= 1950:
4369            # Republic Day
4370            self[date(year, JAN, 26)] = "Republic Day"
4371
4372        if year >= 1947:
4373            # Independence Day
4374            self[date(year, AUG, 15)] = "Independence Day"
4375
4376        # Gandhi Jayanti
4377        self[date(year, OCT, 2)] = "Gandhi Jayanti"
4378
4379        # Labour Day
4380        self[date(year, MAY, 1)] = "Labour Day"
4381
4382        # Christmas
4383        self[date(year, DEC, 25)] = "Christmas"
4384
4385        # GJ: Gujarat
4386        if self.prov == "GJ":
4387            self[date(year, JAN, 14)] = "Uttarayan"
4388            self[date(year, MAY, 1)] = "Gujarat Day"
4389            self[date(year, OCT, 31)] = "Sardar Patel Jayanti"
4390
4391        if self.prov == 'BR':
4392            self[date(year, MAR, 22)] = "Bihar Day"
4393
4394        if self.prov == 'RJ':
4395            self[date(year, MAR, 30)] = "Rajasthan Day"
4396            self[date(year, JUN, 15)] = "Maharana Pratap Jayanti"
4397
4398        if self.prov == 'OD':
4399            self[date(year, APR, 1)] = "Odisha Day (Utkala Dibasa)"
4400            self[date(year, APR, 15)] = "Maha Vishuva Sankranti / Pana" \
4401                                        " Sankranti"
4402
4403        if self.prov in ('OD', 'AP', 'BR', 'WB', 'KL',
4404                         'HR', 'MH', 'UP', 'UK', 'TN'):
4405            self[date(year, APR, 14)] = "Dr. B. R. Ambedkar's Jayanti"
4406
4407        if self.prov == 'TN':
4408            self[date(year, APR, 14)] = "Puthandu (Tamil New Year)"
4409            self[date(year, APR, 15)] = "Puthandu (Tamil New Year)"
4410
4411        if self.prov == 'WB':
4412            self[date(year, APR, 14)] = "Pohela Boishakh"
4413            self[date(year, APR, 15)] = "Pohela Boishakh"
4414            self[date(year, MAY, 9)] = "Rabindra Jayanti"
4415
4416        if self.prov == 'AS':
4417            self[date(year, APR, 15)] = "Bihu (Assamese New Year)"
4418
4419        if self.prov == 'MH':
4420            self[date(year, MAY, 1)] = "Maharashtra Day"
4421
4422        if self.prov == 'SK':
4423            self[date(year, MAY, 16)] = "Annexation Day"
4424
4425        if self.prov == 'KA':
4426            self[date(year, NOV, 1)] = "Karnataka Rajyotsava"
4427
4428        if self.prov == 'AP':
4429            self[date(year, NOV, 1)] = "Andhra Pradesh Foundation Day"
4430
4431        if self.prov == 'HR':
4432            self[date(year, NOV, 1)] = "Haryana Foundation Day"
4433
4434        if self.prov == 'MP':
4435            self[date(year, NOV, 1)] = "Madhya Pradesh Foundation Day"
4436
4437        if self.prov == 'KL':
4438            self[date(year, NOV, 1)] = "Kerala Foundation Day"
4439
4440        if self.prov == 'CG':
4441            self[date(year, NOV, 1)] = "Chhattisgarh Foundation Day"
4442
4443        # TS is Telangana State which was bifurcated in 2014 from AP
4444        # (AndhraPradesh)
4445        if self.prov == 'TS':
4446            self[date(year, OCT, 6)] = "Bathukamma Festival"
4447            self[date(year, APR, 6)] = "Eid al-Fitr"
4448
4449
4450class IND(India):
4451    pass
4452
4453
4454class Croatia(HolidayBase):
4455
4456    # https://en.wikipedia.org/wiki/Public_holidays_in_Croatia
4457
4458    def __init__(self, **kwargs):
4459        self.country = "HR"
4460        HolidayBase.__init__(self, **kwargs)
4461
4462    def _populate(self, year):
4463        # New years
4464        self[date(year, JAN, 1)] = "Nova Godina"
4465        # Epiphany
4466        self[date(year, JAN, 6)] = "Sveta tri kralja"
4467        easter_date = easter(year)
4468
4469        # Easter
4470        self[easter_date] = "Uskrs"
4471        # Easter Monday
4472        self[easter_date + rd(days=1)] = "Uskrsni ponedjeljak"
4473
4474        # Corpus Christi
4475        self[easter_date + rd(days=60)] = "Tijelovo"
4476
4477        # International Workers' Day
4478        self[date(year, MAY, 1)] = "Međunarodni praznik rada"
4479
4480        # Anti-fascist struggle day
4481        self[date(year, JUN, 22)] = "Dan antifašističke borbe"
4482
4483        # Statehood day
4484        self[date(year, JUN, 25)] = "Dan državnosti"
4485
4486        # Victory and Homeland Thanksgiving Day
4487        self[date(year, AUG, 5)] = "Dan pobjede i domovinske zahvalnosti"
4488
4489        # Assumption of Mary
4490        self[date(year, AUG, 15)] = "Velika Gospa"
4491
4492        # Independence Day
4493        self[date(year, OCT, 8)] = "Dan neovisnosti"
4494
4495        # All Saints' Day
4496        self[date(year, NOV, 1)] = "Svi sveti"
4497
4498        # Christmas day
4499        self[date(year, DEC, 25)] = "Božić"
4500
4501        # St. Stephen's day
4502        self[date(year, DEC, 26)] = "Sveti Stjepan"
4503
4504
4505class HR(Croatia):
4506    pass
4507
4508
4509class Luxembourg(HolidayBase):
4510
4511    # https://en.wikipedia.org/wiki/Public_holidays_in_Luxembourg
4512
4513    def __init__(self, **kwargs):
4514        self.country = 'LU'
4515        HolidayBase.__init__(self, **kwargs)
4516
4517    def _populate(self, year):
4518        # Public holidays
4519        self[date(year, JAN, 1)] = "Neijoerschdag"
4520        self[easter(year) + rd(weekday=MO)] = "Ouschterméindeg"
4521        self[date(year, MAY, 1)] = "Dag vun der Aarbecht"
4522        if year >= 2019:
4523            # Europe Day: not in legislation yet, but introduced starting 2019
4524            self[date(year, MAY, 9)] = "Europadag"
4525        self[easter(year) + rd(days=39)] = "Christi Himmelfaart"
4526        self[easter(year) + rd(days=50)] = "Péngschtméindeg"
4527        self[date(year, JUN, 23)] = "Nationalfeierdag"
4528        self[date(year, AUG, 15)] = "Léiffrawëschdag"
4529        self[date(year, NOV, 1)] = "Allerhellgen"
4530        self[date(year, DEC, 25)] = "Chrëschtdag"
4531        self[date(year, DEC, 26)] = "Stiefesdag"
4532
4533
4534class LU(Luxembourg):
4535    pass
4536
4537
4538class Russia(HolidayBase):
4539    """
4540    https://en.wikipedia.org/wiki/Public_holidays_in_Russia
4541    """
4542
4543    def __init__(self, **kwargs):
4544        self.country = "RU"
4545        HolidayBase.__init__(self, **kwargs)
4546
4547    def _populate(self, year):
4548        # New Year's Day
4549        self[date(year, JAN, 1)] = "Новый год"
4550        # New Year's Day
4551        self[date(year, JAN, 2)] = "Новый год"
4552        # New Year's Day
4553        self[date(year, JAN, 3)] = "Новый год"
4554        # New Year's Day
4555        self[date(year, JAN, 4)] = "Новый год"
4556        # New Year's Day
4557        self[date(year, JAN, 5)] = "Новый год"
4558        # New Year's Day
4559        self[date(year, JAN, 6)] = "Новый год"
4560        # Christmas Day (Orthodox)
4561        self[date(year, JAN, 7)] = "Православное Рождество"
4562        # New Year's Day
4563        self[date(year, JAN, 8)] = "Новый год"
4564        # Man Day
4565        self[date(year, FEB, 23)] = "День защитника отечества"
4566        # Women's Day
4567        self[date(year, MAR, 8)] = "День женщин"
4568        # Labour Day
4569        self[date(year, MAY, 1)] = "Праздник Весны и Труда"
4570        # Victory Day
4571        self[date(year, MAY, 9)] = "День Победы"
4572        # Russia's Day
4573        self[date(year, JUN, 12)] = "День России"
4574        # Unity Day
4575        self[date(year, NOV, 4)] = "День народного единства"
4576
4577
4578class RU(Russia):
4579    pass
4580
4581
4582class Lithuania(HolidayBase):
4583
4584    # https://en.wikipedia.org/wiki/Public_holidays_in_Lithuania
4585    # https://www.kalendorius.today/
4586
4587    def __init__(self, **kwargs):
4588        self.country = "LT"
4589        HolidayBase.__init__(self, **kwargs)
4590
4591    def _populate(self, year):
4592        # New Year's Day
4593        self[date(year, 1, 1)] = "Naujieji metai"
4594
4595        # Day of Restoration of the State of Lithuania (1918)
4596        if year >= 1918:
4597            self[date(year, 2, 16)] = "Lietuvos valstybės " \
4598                                      "atkūrimo diena"
4599
4600        # Day of Restoration of Independence of Lithuania
4601        # (from the Soviet Union, 1990)
4602        if year >= 1990:
4603            self[date(year, 3, 11)] = "Lietuvos nepriklausomybės " \
4604                                      "atkūrimo diena"
4605
4606        # Easter
4607        easter_date = easter(year)
4608        self[easter_date] = "Velykos"
4609
4610        # Easter 2nd day
4611        self[easter_date + rd(days=1)] = "Velykų antroji diena"
4612
4613        # International Workers' Day
4614        self[date(year, 5, 1)] = "Tarptautinė darbo diena"
4615
4616        # Mother's day. First Sunday in May
4617        self[date(year, 5, 1) + rd(weekday=SU)] = "Motinos diena"
4618
4619        # Fathers's day. First Sunday in June
4620        self[date(year, 6, 1) + rd(weekday=SU)] = "Tėvo diena"
4621
4622        # St. John's Day [Christian name],
4623        # Day of Dew [original pagan name]
4624        if year >= 2003:
4625            self[date(year, 6, 24)] = "Joninės, Rasos"
4626
4627        # Statehood Day
4628        if year >= 1991:
4629            self[date(year, 7, 6)] = "Valstybės (Lietuvos " \
4630                                     "karaliaus Mindaugo " \
4631                                     "karūnavimo) diena"
4632
4633        # Assumption Day
4634        self[date(year, 8, 15)] = "Žolinė (Švč. Mergelės " \
4635                                  "Marijos ėmimo į dangų diena)"
4636
4637        # All Saints' Day
4638        self[date(year, 11, 1)] = "Visų šventųjų diena (Vėlinės)"
4639
4640        # Christmas Eve
4641        self[date(year, 12, 24)] = "Šv. Kūčios"
4642
4643        # Christmas 1st day
4644        self[date(year, 12, 25)] = "Šv. Kalėdų pirma diena"
4645
4646        # Christmas 2nd day
4647        self[date(year, 12, 26)] = "Šv. Kalėdų antra diena"
4648
4649
4650class LT(Lithuania):
4651    pass
4652
4653
4654class Estonia(HolidayBase):
4655    def __init__(self, **kwargs):
4656        self.country = "EE"
4657        HolidayBase.__init__(self, **kwargs)
4658
4659    def _populate(self, year):
4660        e = easter(year)
4661
4662        # New Year's Day
4663        self[date(year, JAN, 1)] = "uusaasta"
4664
4665        # Independence Day, anniversary of the Republic of Estonia
4666        self[date(year, FEB, 24)] = "iseseisvuspäev"
4667
4668        # Good Friday
4669        self[e - rd(days=2)] = "suur reede"
4670
4671        # Easter Sunday
4672        self[e] = "ülestõusmispühade 1. püha"
4673
4674        # Spring Day
4675        self[date(year, MAY, 1)] = "kevadpüha"
4676
4677        # Pentecost
4678        self[e + rd(days=49)] = "nelipühade 1. püha"
4679
4680        # Victory Day
4681        self[date(year, JUN, 23)] = "võidupüha"
4682
4683        # Midsummer Day
4684        self[date(year, JUN, 24)] = "jaanipäev"
4685
4686        # Day of Restoration of Independence
4687        self[date(year, AUG, 20)] = "taasiseseisvumispäev"
4688
4689        # Christmas Eve
4690        self[date(year, DEC, 24)] = "jõululaupäev"
4691
4692        # Christmas Day
4693        self[date(year, DEC, 25)] = "esimene jõulupüha"
4694
4695        # Boxing Day
4696        self[date(year, DEC, 26)] = "teine jõulupüha"
4697
4698
4699class EE(Estonia):
4700    pass
4701
4702
4703class Iceland(HolidayBase):
4704    # https://en.wikipedia.org/wiki/Public_holidays_in_Iceland
4705    # https://www.officeholidays.com/countries/iceland/index.php
4706    def __init__(self, **kwargs):
4707        self.country = "IS"
4708        HolidayBase.__init__(self, **kwargs)
4709
4710    def _populate(self, year):
4711        # Public holidays
4712        self[date(year, JAN, 1)] = "Nýársdagur"
4713        self[easter(year) - rd(days=3)] = "Skírdagur"
4714        self[easter(year) + rd(weekday=FR(-1))] = "Föstudagurinn langi"
4715        self[easter(year)] = "Páskadagur"
4716        self[easter(year) + rd(days=1)] = "Annar í páskum"
4717        self[date(year, APR, 19) + rd(weekday=TH(+1))] = \
4718            "Sumardagurinn fyrsti"
4719        self[date(year, MAY, 1)] = "Verkalýðsdagurinn"
4720        self[easter(year) + rd(days=39)] = "Uppstigningardagur"
4721        self[easter(year) + rd(days=49)] = "Hvítasunnudagur"
4722        self[easter(year) + rd(days=50)] = "Annar í hvítasunnu"
4723        self[date(year, JUN, 17)] = "Þjóðhátíðardagurinn"
4724        # First Monday of August
4725        self[date(year, AUG, 1) + rd(weekday=MO(+1))] = \
4726            "Frídagur verslunarmanna"
4727        self[date(year, DEC, 24)] = "Aðfangadagur"
4728        self[date(year, DEC, 25)] = "Jóladagur"
4729        self[date(year, DEC, 26)] = "Annar í jólum"
4730        self[date(year, DEC, 31)] = "Gamlársdagur"
4731
4732
4733class IS(Iceland):
4734    pass
4735
4736
4737class Kenya(HolidayBase):
4738    # https://en.wikipedia.org/wiki/Public_holidays_in_Kenya
4739    # http://kenyaembassyberlin.de/Public-Holidays-in-Kenya.48.0.html
4740    def __init__(self, **kwargs):
4741        self.country = "KE"
4742        HolidayBase.__init__(self, **kwargs)
4743
4744    def _populate(self, year):
4745        # Public holidays
4746        self[date(year, JAN, 1)] = "New Year's Day"
4747        self[date(year, MAY, 1)] = "Labour Day"
4748        self[date(year, JUN, 1)] = "Madaraka Day"
4749        self[date(year, OCT, 20)] = "Mashujaa Day"
4750        self[date(year, DEC, 12)] = "Jamhuri (Independence) Day"
4751        self[date(year, DEC, 25)] = "Christmas Day"
4752        self[date(year, DEC, 26)] = "Boxing Day"
4753        for k, v in list(self.items()):
4754            if self.observed and k.weekday() == SUN:
4755                self[k + rd(days=1)] = v + " (Observed)"
4756
4757        self[easter(year) - rd(weekday=FR(-1))] = "Good Friday"
4758        self[easter(year) + rd(weekday=MO(+1))] = "Easter Monday"
4759
4760
4761class KE(Kenya):
4762    pass
4763
4764
4765class HongKong(HolidayBase):
4766
4767    # https://www.gov.hk/en/about/abouthk/holiday/2020.htm
4768    # https://en.wikipedia.org/wiki/Public_holidays_in_Hong_Kong
4769
4770    def __init__(self, **kwargs):
4771        self.country = "HK"
4772        HolidayBase.__init__(self, **kwargs)
4773
4774    def _populate(self, year):
4775
4776        day_following = "The day following "
4777
4778        # The first day of January
4779        name = "The first day of January"
4780        first_date = date(year, JAN, 1)
4781        if self.observed:
4782            if first_date.weekday() == SUN:
4783                self[first_date + rd(days=+1)] = day_following + \
4784                    self.first_lower(name)
4785                first_date = first_date + rd(days=+1)
4786            else:
4787                self[first_date] = name
4788        else:
4789            self[first_date] = name
4790
4791        # Lunar New Year
4792        name = "Lunar New Year's Day"
4793        preceding_day_lunar = "The day preceding Lunar New Year's Day"
4794        second_day_lunar = "The second day of Lunar New Year"
4795        third_day_lunar = "The third day of Lunar New Year"
4796        fourth_day_lunar = "The fourth day of Lunar New Year"
4797        dt = self.get_solar_date(year, 1, 1)
4798        new_year_date = date(dt.year, dt.month, dt.day)
4799        if self.observed:
4800            self[new_year_date] = name
4801            if new_year_date.weekday() in [MON, TUE, WED, THU]:
4802                self[new_year_date] = name
4803                self[new_year_date + rd(days=+1)] = second_day_lunar
4804                self[new_year_date + rd(days=+2)] = third_day_lunar
4805            elif new_year_date.weekday() == FRI:
4806                self[new_year_date] = name
4807                self[new_year_date + rd(days=+1)] = second_day_lunar
4808                self[new_year_date + rd(days=+3)] = fourth_day_lunar
4809            elif new_year_date.weekday() == SAT:
4810                self[new_year_date] = name
4811                self[new_year_date + rd(days=+2)] = third_day_lunar
4812                self[new_year_date + rd(days=+3)] = fourth_day_lunar
4813            elif new_year_date.weekday() == SUN:
4814                if year in [2006, 2007, 2010]:
4815                    self[new_year_date + rd(days=-1)] = preceding_day_lunar
4816                    self[new_year_date + rd(days=+1)] = second_day_lunar
4817                    self[new_year_date + rd(days=+2)] = third_day_lunar
4818                else:
4819                    self[new_year_date + rd(days=+1)] = second_day_lunar
4820                    self[new_year_date + rd(days=+2)] = third_day_lunar
4821                    self[new_year_date + rd(days=+3)] = fourth_day_lunar
4822        else:
4823            self[new_year_date] = name
4824            self[new_year_date + rd(days=+1)] = second_day_lunar
4825            self[new_year_date + rd(days=+2)] = third_day_lunar
4826
4827        # Ching Ming Festival
4828        name = "Ching Ming Festival"
4829        if self.isLeapYear(year) or (self.isLeapYear(year-1) and year > 2008):
4830            ching_ming_date = date(year, APR, 4)
4831        else:
4832            ching_ming_date = date(year, APR, 5)
4833        if self.observed:
4834            if ching_ming_date.weekday() == SUN:
4835                self[ching_ming_date + rd(days=+1)] = day_following + name
4836                ching_ming_date = ching_ming_date + rd(days=+1)
4837            else:
4838                self[ching_ming_date] = name
4839        else:
4840            self[ching_ming_date] = name
4841
4842        # Easter Holiday
4843        good_friday = "Good Friday"
4844        easter_monday = "Easter Monday"
4845        if self.observed:
4846            self[easter(year) + rd(weekday=FR(-1))] = good_friday
4847            self[easter(year) + rd(weekday=SA(-1))] = day_following + \
4848                good_friday
4849            if ching_ming_date == easter(year) + rd(weekday=MO):
4850                self[easter(year) + rd(weekday=MO) + rd(days=+1)] = \
4851                    day_following + easter_monday
4852            else:
4853                self[easter(year) + rd(weekday=MO)] = easter_monday
4854        else:
4855            self[easter(year) + rd(weekday=FR(-1))] = good_friday
4856            self[easter(year) + rd(weekday=SA(-1))] = day_following + \
4857                good_friday
4858            self[easter(year) + rd(weekday=MO)] = easter_monday
4859
4860        # Birthday of the Buddha
4861        name = "Birthday of the Buddha"
4862        dt = self.get_solar_date(year, 4, 8)
4863        buddha_date = date(dt.year, dt.month, dt.day)
4864        if self.observed:
4865            if buddha_date.weekday() == SUN:
4866                self[buddha_date + rd(days=+1)] = day_following + name
4867            else:
4868                self[buddha_date] = name
4869        else:
4870            self[buddha_date] = name
4871
4872        # Labour Day
4873        name = "Labour Day"
4874        labour_date = date(year, MAY, 1)
4875        if self.observed:
4876            if labour_date.weekday() == SUN:
4877                self[labour_date + rd(days=+1)] = day_following + name
4878            else:
4879                self[labour_date] = name
4880        else:
4881            self[labour_date] = name
4882
4883        # Tuen Ng Festival
4884        name = "Tuen Ng Festival"
4885        dt = self.get_solar_date(year, 5, 5)
4886        tuen_ng_date = date(dt.year, dt.month, dt.day)
4887        if self.observed:
4888            if tuen_ng_date.weekday() == SUN:
4889                self[tuen_ng_date + rd(days=+1)] = day_following + name
4890            else:
4891                self[tuen_ng_date] = name
4892        else:
4893            self[tuen_ng_date] = name
4894
4895        # Hong Kong Special Administrative Region Establishment Day
4896        name = "Hong Kong Special Administrative Region Establishment Day"
4897        hksar_date = date(year, JUL, 1)
4898        if self.observed:
4899            if hksar_date.weekday() == SUN:
4900                self[hksar_date + rd(days=+1)] = day_following + name
4901            else:
4902                self[hksar_date] = name
4903        else:
4904            self[hksar_date] = name
4905
4906        # Special holiday on 2015 - The 70th anniversary day of the victory
4907        # of the Chinese people's war of resistance against Japanese aggression
4908        name = "The 70th anniversary day of the victory of the Chinese " + \
4909            "people's war of resistance against Japanese aggression"
4910        if year == 2015:
4911            self[date(year, SEP, 3)] = name
4912
4913        # Chinese Mid-Autumn Festival
4914        name = "Chinese Mid-Autumn Festival"
4915        dt = self.get_solar_date(year, 8, 15)
4916        mid_autumn_date = date(dt.year, dt.month, dt.day)
4917        if self.observed:
4918            if mid_autumn_date.weekday() == SAT:
4919                self[mid_autumn_date] = name
4920            else:
4921                self[mid_autumn_date + rd(days=+1)] = day_following + \
4922                    "the " + name
4923            mid_autumn_date = mid_autumn_date + rd(days=+1)
4924        else:
4925            self[mid_autumn_date] = name
4926
4927        # National Day
4928        name = "National Day"
4929        national_date = date(year, OCT, 1)
4930        if self.observed:
4931            if (national_date.weekday() == SUN or
4932                    national_date == mid_autumn_date):
4933                self[national_date + rd(days=+1)] = day_following + name
4934            else:
4935                self[national_date] = name
4936        else:
4937            self[national_date] = name
4938
4939        # Chung Yeung Festival
4940        name = "Chung Yeung Festival"
4941        dt = self.get_solar_date(year, 9, 9)
4942        chung_yeung_date = date(dt.year, dt.month, dt.day)
4943        if self.observed:
4944            if chung_yeung_date.weekday() == SUN:
4945                self[chung_yeung_date + rd(days=+1)] = day_following + name
4946            else:
4947                self[chung_yeung_date] = name
4948        else:
4949            self[chung_yeung_date] = name
4950
4951        # Christmas Day
4952        name = "Christmas Day"
4953        first_after_christmas = "The first weekday after " + name
4954        second_after_christmas = "The second weekday after " + name
4955        christmas_date = date(year, DEC, 25)
4956        if self.observed:
4957            if christmas_date.weekday() == SUN:
4958                self[christmas_date] = name
4959                self[christmas_date + rd(days=+1)] = first_after_christmas
4960                self[christmas_date + rd(days=+2)] = second_after_christmas
4961            elif christmas_date.weekday() == SAT:
4962                self[christmas_date] = name
4963                self[christmas_date + rd(days=+2)] = first_after_christmas
4964            else:
4965                self[christmas_date] = name
4966                self[christmas_date + rd(days=+1)] = first_after_christmas
4967        else:
4968            self[christmas_date] = name
4969            self[christmas_date + rd(days=+1)] = day_following + name
4970
4971    def isLeapYear(self, year):
4972        if year % 4 != 0:
4973            return False
4974        elif year % 100 != 0:
4975            return True
4976        elif year % 400 != 0:
4977            return False
4978        else:
4979            return True
4980
4981    def first_lower(self, s):
4982        return s[0].lower() + s[1:]
4983
4984    # Store the number of days per year from 1901 to 2099, and the number of
4985    # days from the 1st to the 13th to store the monthly (including the month
4986    # of the month), 1 means that the month is 30 days. 0 means the month is
4987    # 29 days. The 12th to 15th digits indicate the month of the next month.
4988    # If it is 0x0F, it means that there is no leap month.
4989    g_lunar_month_days = [
4990        0xF0EA4, 0xF1D4A, 0x52C94, 0xF0C96, 0xF1536,
4991        0x42AAC, 0xF0AD4, 0xF16B2, 0x22EA4, 0xF0EA4,  # 1901-1910
4992        0x6364A, 0xF164A, 0xF1496, 0x52956, 0xF055A,
4993        0xF0AD6, 0x216D2, 0xF1B52, 0x73B24, 0xF1D24,  # 1911-1920
4994        0xF1A4A, 0x5349A, 0xF14AC, 0xF056C, 0x42B6A,
4995        0xF0DA8, 0xF1D52, 0x23D24, 0xF1D24, 0x61A4C,  # 1921-1930
4996        0xF0A56, 0xF14AE, 0x5256C, 0xF16B4, 0xF0DA8,
4997        0x31D92, 0xF0E92, 0x72D26, 0xF1526, 0xF0A56,  # 1931-1940
4998        0x614B6, 0xF155A, 0xF0AD4, 0x436AA, 0xF1748,
4999        0xF1692, 0x23526, 0xF152A, 0x72A5A, 0xF0A6C,  # 1941-1950
5000        0xF155A, 0x52B54, 0xF0B64, 0xF1B4A, 0x33A94,
5001        0xF1A94, 0x8152A, 0xF152E, 0xF0AAC, 0x6156A,  # 1951-1960
5002        0xF15AA, 0xF0DA4, 0x41D4A, 0xF1D4A, 0xF0C94,
5003        0x3192E, 0xF1536, 0x72AB4, 0xF0AD4, 0xF16D2,  # 1961-1970
5004        0x52EA4, 0xF16A4, 0xF164A, 0x42C96, 0xF1496,
5005        0x82956, 0xF055A, 0xF0ADA, 0x616D2, 0xF1B52,  # 1971-1980
5006        0xF1B24, 0x43A4A, 0xF1A4A, 0xA349A, 0xF14AC,
5007        0xF056C, 0x60B6A, 0xF0DAA, 0xF1D92, 0x53D24,  # 1981-1990
5008        0xF1D24, 0xF1A4C, 0x314AC, 0xF14AE, 0x829AC,
5009        0xF06B4, 0xF0DAA, 0x52D92, 0xF0E92, 0xF0D26,  # 1991-2000
5010        0x42A56, 0xF0A56, 0xF14B6, 0x22AB4, 0xF0AD4,
5011        0x736AA, 0xF1748, 0xF1692, 0x53526, 0xF152A,  # 2001-2010
5012        0xF0A5A, 0x4155A, 0xF156A, 0x92B54, 0xF0BA4,
5013        0xF1B4A, 0x63A94, 0xF1A94, 0xF192A, 0x42A5C,  # 2011-2020
5014        0xF0AAC, 0xF156A, 0x22B64, 0xF0DA4, 0x61D52,
5015        0xF0E4A, 0xF0C96, 0x5192E, 0xF1956, 0xF0AB4,  # 2021-2030
5016        0x315AC, 0xF16D2, 0xB2EA4, 0xF16A4, 0xF164A,
5017        0x63496, 0xF1496, 0xF0956, 0x50AB6, 0xF0B5A,  # 2031-2040
5018        0xF16D4, 0x236A4, 0xF1B24, 0x73A4A, 0xF1A4A,
5019        0xF14AA, 0x5295A, 0xF096C, 0xF0B6A, 0x31B54,  # 2041-2050
5020        0xF1D92, 0x83D24, 0xF1D24, 0xF1A4C, 0x614AC,
5021        0xF14AE, 0xF09AC, 0x40DAA, 0xF0EAA, 0xF0E92,  # 2051-2060
5022        0x31D26, 0xF0D26, 0x72A56, 0xF0A56, 0xF14B6,
5023        0x52AB4, 0xF0AD4, 0xF16CA, 0x42E94, 0xF1694,  # 2061-2070
5024        0x8352A, 0xF152A, 0xF0A5A, 0x6155A, 0xF156A,
5025        0xF0B54, 0x4174A, 0xF1B4A, 0xF1A94, 0x3392A,  # 2071-2080
5026        0xF192C, 0x7329C, 0xF0AAC, 0xF156A, 0x52B64,
5027        0xF0DA4, 0xF1D4A, 0x41C94, 0xF0C96, 0x8192E,  # 2081-2090
5028        0xF0956, 0xF0AB6, 0x615AC, 0xF16D4, 0xF0EA4,
5029        0x42E4A, 0xF164A, 0xF1516, 0x22936,           # 2090-2099
5030    ]
5031    # Define range of years
5032    START_YEAR, END_YEAR = 1901, 1900 + len(g_lunar_month_days)
5033    # 1901 The 1st day of the 1st month of the Gregorian calendar is 1901/2/19
5034    LUNAR_START_DATE, SOLAR_START_DATE = (1901, 1, 1), datetime(1901, 2, 19)
5035    # The Gregorian date for December 30, 2099 is 2100/2/8
5036    LUNAR_END_DATE, SOLAR_END_DATE = (2099, 12, 30), datetime(2100, 2, 18)
5037
5038    def get_leap_month(self, lunar_year):
5039        return (self.g_lunar_month_days[lunar_year-self.START_YEAR] >> 16) \
5040            & 0x0F
5041
5042    def lunar_month_days(self, lunar_year, lunar_month):
5043        return 29 + ((self.g_lunar_month_days[lunar_year-self.START_YEAR] >>
5044                      lunar_month) & 0x01)
5045
5046    def lunar_year_days(self, year):
5047        days = 0
5048        months_day = self.g_lunar_month_days[year - self.START_YEAR]
5049        for i in range(1, 13 if self.get_leap_month(year) == 0x0F else 14):
5050            day = 29 + ((months_day >> i) & 0x01)
5051            days += day
5052        return days
5053
5054    # Calculate the Gregorian date according to the lunar calendar
5055    def get_solar_date(self, year, month, day):
5056        span_days = 0
5057        for y in range(self.START_YEAR, year):
5058            span_days += self.lunar_year_days(y)
5059        leap_month = self.get_leap_month(year)
5060        for m in range(1, month + (month > leap_month)):
5061            span_days += self.lunar_month_days(year, m)
5062        span_days += day - 1
5063        return self.SOLAR_START_DATE + timedelta(span_days)
5064
5065
5066class HK(HongKong):
5067    pass
5068
5069
5070class Peru(HolidayBase):
5071    # https://www.gob.pe/feriados
5072    # https://es.wikipedia.org/wiki/Anexo:Días_feriados_en_el_Perú
5073    def __init__(self, **kwargs):
5074        self.country = "PE"
5075        HolidayBase.__init__(self, **kwargs)
5076
5077    def _populate(self, year):
5078        # New Year's Day
5079        self[date(year, JAN, 1)] = "Año Nuevo [New Year's Day]"
5080
5081        # Feast of Saints Peter and Paul
5082        name = "San Pedro y San Pablo [Feast of Saints Peter and Paul]"
5083        self[date(year, JUN, 29)] = name
5084
5085        # Independence Day
5086        name = "Día de la Independencia [Independence Day]"
5087        self[date(year, JUL, 28)] = name
5088
5089        name = "Día de las Fuerzas Armadas y la Policía del Perú"
5090        self[date(year, JUL, 29)] = name
5091
5092        # Santa Rosa de Lima
5093        name = "Día de Santa Rosa de Lima"
5094        self[date(year, AUG, 30)] = name
5095
5096        # Battle of Angamos
5097        name = "Combate Naval de Angamos [Battle of Angamos]"
5098        self[date(year, OCT, 8)] = name
5099
5100        # Holy Thursday
5101        self[easter(year) + rd(weekday=TH(-1))
5102             ] = "Jueves Santo [Maundy Thursday]"
5103
5104        # Good Friday
5105        self[easter(year) + rd(weekday=FR(-1))
5106             ] = "Viernes Santo [Good Friday]"
5107
5108        # Holy Saturday
5109        self[easter(year) + rd(weekday=SA(-1))
5110             ] = "Sábado de Gloria [Holy Saturday]"
5111
5112        # Easter Sunday
5113        self[easter(year) + rd(weekday=SU(-1))
5114             ] = "Domingo de Resurrección [Easter Sunday]"
5115
5116        # Labor Day
5117        self[date(year, MAY, 1)] = "Día del Trabajo [Labour Day]"
5118
5119        # All Saints Day
5120        name = "Día de Todos Los Santos [All Saints Day]"
5121        self[date(year, NOV, 1)] = name
5122
5123        # Inmaculada Concepción
5124        name = "Inmaculada Concepción [Immaculate Conception]"
5125        self[date(year, DEC, 8)] = name
5126
5127        # Christmas
5128        self[date(year, DEC, 25)] = "Navidad [Christmas]"
5129
5130
5131class PE(Peru):
5132    pass
5133
5134
5135class Nigeria(HolidayBase):
5136    # https://en.wikipedia.org/wiki/Public_holidays_in_Nigeria
5137    def __init__(self, **kwargs):
5138        self.country = "NG"
5139        HolidayBase.__init__(self, **kwargs)
5140
5141    def _populate(self, year):
5142        # New Year's Day
5143        self[date(year, JAN, 1)] = "New Year's day"
5144
5145        # Worker's day
5146        self[date(year, MAY, 1)] = "Worker's day"
5147
5148        # Children's day
5149        self[date(year, MAY, 27)] = "Children's day"
5150
5151        # Democracy day
5152        self[date(year, JUN, 12)] = "Democracy day"
5153
5154        # Independence Day
5155        self[date(year, OCT, 1)] = "Independence day"
5156
5157        # Christmas day
5158        self[date(year, DEC, 25)] = "Christmas day"
5159
5160        # Boxing day
5161        self[date(year, DEC, 26)] = "Boxing day"
5162
5163
5164class NG(Nigeria):
5165    pass
5166
5167
5168class DominicanRepublic(HolidayBase):
5169    # http://ojd.org.do/Normativas/LABORAL/Leyes/Ley%20No.%20%20139-97.pdf
5170    # https://es.wikipedia.org/wiki/Rep%C3%BAblica_Dominicana#D%C3%ADas_festivos_nacionales
5171
5172    def __init__(self, **kwargs):
5173        self.country = 'DO'
5174        HolidayBase.__init__(self, **kwargs)
5175
5176    @staticmethod
5177    def __change_day_by_law(holiday, latest_days=(3, 4)):
5178        # Law No. 139-97 - Holidays Dominican Republic - Jun 27, 1997
5179        if holiday >= date(1997, 6, 27):
5180            if holiday.weekday() in [1, 2]:
5181                holiday -= rd(weekday=MO(-1))
5182            elif holiday.weekday() in latest_days:
5183                holiday += rd(weekday=MO(1))
5184        return holiday
5185
5186    def _populate(self, year):
5187        # New Year's Day
5188        self[date(year, JAN, 1)] = "Año Nuevo [New Year's Day]"
5189
5190        # Epiphany
5191        epiphany_day = self.__change_day_by_law(date(year, JAN, 6))
5192        self[epiphany_day] = "Día de los Santos Reyes [Epiphany]"
5193
5194        # Lady of Altagracia
5195        self[date(year, JAN, 21)] = "Día de la Altagracia [Lady of Altagracia]"
5196
5197        # Juan Pablo Duarte Day
5198        duarte_day = self.__change_day_by_law(date(year, JAN, 26))
5199        self[duarte_day] = "Día de Duarte [Juan Pablo Duarte Day]"
5200
5201        # Independence Day
5202        self[date(year, FEB, 27)] = "Día de Independencia [Independence Day]"
5203
5204        # Good Friday
5205        self[easter(year) + rd(weekday=FR(-1))] = "Viernes Santo [Good Friday]"
5206
5207        # Labor Day
5208        labor_day = self.__change_day_by_law(date(year, MAY, 1), (3, 4, 6))
5209        self[labor_day] = "Día del Trabajo [Labor Day]"
5210
5211        # Feast of Corpus Christi
5212        self[date(year, JUN, 11)] = "Corpus Christi [Feast of Corpus Christi]"
5213
5214        # Restoration Day
5215        # Judgment No. 14 of Feb 20, 2008 of the Supreme Court of Justice
5216        restoration_day = date(year, AUG, 16) if ((year - 2000) % 4 == 0) \
5217            and year < 2008 else self.__change_day_by_law(date(year, AUG, 16))
5218        self[restoration_day] = "Día de la Restauración [Restoration Day]"
5219
5220        # Our Lady of Mercedes Day
5221        self[date(year, SEP, 24)] = "Día de las Mercedes \
5222            [Our Lady of Mercedes Day]"
5223
5224        # Constitution Day
5225        constitution_day = self.__change_day_by_law(date(year, NOV, 6))
5226        self[constitution_day] = "Día de la Constitución [Constitution Day]"
5227
5228        # Christmas Day
5229        self[date(year, DEC, 25)] = "Día de Navidad [Christmas Day]"
5230
5231
5232class DO(DominicanRepublic):
5233    pass
5234
5235
5236class Nicaragua(HolidayBase):
5237    PROVINCES = ['MN']
5238
5239    def __init__(self, **kwargs):
5240        self.country = 'NI'
5241        self.prov = kwargs.pop('prov', kwargs.pop('state', 'MN'))
5242        HolidayBase.__init__(self, **kwargs)
5243
5244    def _populate(self, year):
5245        # New Years
5246        self[date(year, JAN, 1)] = "Año Nuevo [New Year's Day]"
5247        # Maundy Thursday
5248        self[easter(year) + rd(weekday=TH(-1))] =\
5249            "Jueves Santo [Maundy Thursday]"
5250        # Good Friday
5251        self[easter(year) + rd(weekday=FR(-1))] = "Viernes Santo [Good Friday]"
5252        # Labor Day
5253        self[date(year, MAY, 1)] = "Día del Trabajo [Labour Day]"
5254        # Revolution Day
5255        if 2020 >= year >= 1979:
5256            self[date(year, JUL, 19)] = "Día de la Revolución [Revolution Day]"
5257        # Battle of San Jacinto Day
5258        self[date(year, SEP, 14)] =\
5259            "Batalla de San Jacinto [Battle of San Jacinto]"
5260        # Independence Day
5261        self[date(year, SEP, 15)] =\
5262            "Día de la Independencia [Independence Day]"
5263        # Virgin's Day
5264        self[date(year, DEC, 8)] = "Concepción de María [Virgin's Day]"
5265        # Christmas
5266        self[date(year, DEC, 25)] = "Navidad [Christmas]"
5267
5268        # Provinces festive day
5269        if self.prov:
5270            if self.prov == 'MN':
5271                # Santo Domingo Day Down
5272                self[date(year, AUG, 1)] = "Bajada de Santo Domingo"
5273                # Santo Domingo Day Up
5274                self[date(year, AUG, 10)] = "Subida de Santo Domingo"
5275
5276
5277class NI(Nicaragua):
5278    pass
5279