diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7fa5420e8..dfefb94da 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -34,9 +34,10 @@ Your PR description goes here. --> - [ ] I've followed the [contributing guidelines][contributing-guidelines] +- [ ] I've added references to all holidays information sources used in this PR - [ ] This PR is filed against `beta` branch of the repository - [ ] This PR doesn't contain any merge conflicts and has clean commit history -- [ ] The code style looks good: `make pre-commit` +- [ ] The code style looks good: `make pre-commit` command generates no changes - [ ] All tests pass locally: `make test`, `make tox` (we strongly encourage adding tests to your code) - [ ] The related [documentation][docs] has been added/updated (check off the box for free if no updates is required) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 1a1104aaa..e380ea560 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -1,5 +1,5 @@ name: Tests -on: [push, pull_request, workflow_dispatch] +on: [merge_group, push, pull_request, workflow_dispatch] env: FORCE_COLOR: 1 @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check Out Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set Up Python uses: actions/setup-python@v4.7.0 with: @@ -28,7 +28,7 @@ jobs: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', 'pypy-3.8'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set Up Python ${{ matrix.python-version }} uses: actions/setup-python@v4.7.0 with: @@ -58,7 +58,7 @@ jobs: needs: [test] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set Up Python uses: actions/setup-python@v4.7.0 with: diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 0613b9b03..07c67ff89 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -1,4 +1,4 @@ -name: Pre-commit hooks autoupdate +name: Update pre-commit hooks on: schedule: @@ -7,18 +7,25 @@ on: jobs: auto-update: + name: Update pre-commit hooks + if: ${{ github.repository }} == "vacanza/python-holidays" + permissions: + contents: write + pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4.7.0 + with: + python-version: "3.11" - uses: browniebroke/pre-commit-autoupdate-action@v1.0.0 - uses: peter-evans/create-pull-request@v5.0.2 with: base: beta - branch: update/pre-commit-hooks - title: Update pre-commit hooks - author: github-actions[bot] + body: Update pre-commit hooks to their latest versions. + branch: update-pre-commit-hooks commit-message: "Chore: Update pre-commit hooks" committer: github-actions[bot] - body: Update versions of pre-commit hooks to latest version. + delete-branch: true + title: Update pre-commit hooks token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4b8f6f03a..099b60c77 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/python/black - rev: 23.7.0 + rev: 23.9.1 hooks: - id: black exclude: ^(docs) @@ -50,7 +50,7 @@ repos: - id: rst-backticks - repo: https://github.com/myint/rstcheck - rev: v6.1.2 + rev: v6.2.0 hooks: - id: rstcheck additional_dependencies: [rstcheck, sphinx] diff --git a/CHANGES b/CHANGES index 05df9b91a..a900a29b4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,26 @@ +Version 0.33 +============ + +Released September 18, 2023 + +- Add merge queue support (#1464 by @arkid15r) +- Introduce ObservedHolidays class (#1444 by @KJhellico, @arkid15r) +- Update Algeria holidays: add fr localization (#1467 by @abh31000) +- Fix README.rst (#1472 by @KJhellico) +- Update Belgium holidays: add bank holidays (#1457 by @KJhellico) +- Update Brazil holidays: specify optional holidays (#1452 by @KJhellico) +- Update Canada holidays (#1448 by @KJhellico) +- Update Liechtenstein holidays: specify bank holidays (#1462 by @KJhellico) +- Update PR template (#1461 by @arkid15r) +- Update Thailand holidays: add holiday categories (#1346 by @PPsyrius, @arkid15r, @KJhellico) +- Update United Kingdom holidays (#1454 by @KJhellico) +- Update documentation: add language usage example to examples.rst (#1456 by @jovana, @arkid15r, @KJhellico) +- Update l10n files: fix ar, en_US headers (#1468 by @abh31000) +- Update pre commit automatic update workflow (#1469 by @arkid15r) +- Update skipIf rules for heavy tests (#1460 by @arkid15r) +- Migrate remaining countries to ObservedHolidayBase (#1463 by @KJhellico) +- Tune pre-commit auto-update workflow (#1473 by @arkid15r) + Version 0.32 ============ diff --git a/README.rst b/README.rst index e2c55c314..ffddb6cdb 100644 --- a/README.rst +++ b/README.rst @@ -45,7 +45,7 @@ Install The latest stable version can always be installed or updated via pip: -.. code-block:: bash +.. code-block:: shell $ pip install --upgrade holidays @@ -140,7 +140,7 @@ The list of supported countries, their subdivisions and supported languages * - Algeria - DZ - - - **ar**, en_US + - **ar**, en_US, fr * - American Samoa - AS - Can also be loaded as country US, subdivision AS @@ -243,7 +243,7 @@ The list of supported countries, their subdivisions and supported languages - * - Canada - CA - - Provinces and territories: AB, BC, MB, NB, NL, NS, NT, NU, **ON**, PE, QC, SK, YT + - Provinces and territories: AB, BC, MB, NB, NL, NS, NT, NU, ON, PE, QC, SK, YT - ar, **en**, fr, th * - Chad - TD @@ -705,7 +705,7 @@ Beta Version The latest development (beta) version can be installed directly from GitHub: -.. code-block:: bash +.. code-block:: shell $ pip install --upgrade https://github.com/vacanza/python-holidays/tarball/beta diff --git a/docs/source/examples.rst b/docs/source/examples.rst index 44284c6ca..6f31393f7 100644 --- a/docs/source/examples.rst +++ b/docs/source/examples.rst @@ -123,6 +123,25 @@ fly and the holiday list will be adjusted accordingly: >> date(2012, 1, 2) in us_holidays True +Language support +---------------- +To change the language translation, you can set the language explicitly. + +.. code-block:: python + + >>> for dt, name in sorted(holidays.ES(years=2023, language="es").items()): + >>> print(dt, name) + 2023-01-06 Epifanía del Señor + 2023-04-06 Jueves Santo + 2023-04-07 Viernes Santo + 2023-05-01 Día del Trabajador + 2023-08-15 Asunción de la Virgen + 2023-10-12 Día de la Hispanidad + 2023-11-01 Todos los Santos + 2023-12-06 Día de la Constitución Española + 2023-12-08 La Inmaculada Concepción + 2023-12-25 Navidad + Date from holiday name ---------------------- diff --git a/holidays/__init__.py b/holidays/__init__.py index f00e4eb95..5639dd652 100644 --- a/holidays/__init__.py +++ b/holidays/__init__.py @@ -16,7 +16,7 @@ from holidays.registry import EntityLoader from holidays.utils import * -__version__ = "0.32" +__version__ = "0.33" EntityLoader.load("countries", globals()) diff --git a/holidays/constants.py b/holidays/constants.py index e18e65873..d32ed101d 100644 --- a/holidays/constants.py +++ b/holidays/constants.py @@ -37,10 +37,11 @@ HOLIDAY_NAME_DELIMITER = "; " # Holiday names separator. # Supported holiday categories. +ARMED_FORCES = "armed_forces" BANK = "bank" -EXTENDED = "extended" GOVERNMENT = "government" HALF_DAY = "half_day" +OPTIONAL = "optional" PUBLIC = "public" SCHOOL = "school" WORKDAY = "workday" @@ -52,15 +53,16 @@ ISLAMIC = "islamic" ALL_CATEGORIES = { + ARMED_FORCES, BANK, CHINESE, CHRISTIAN, - EXTENDED, GOVERNMENT, HALF_DAY, HEBREW, HINDU, ISLAMIC, + OPTIONAL, PUBLIC, SCHOOL, WORKDAY, diff --git a/holidays/countries/albania.py b/holidays/countries/albania.py index c83ce0b8c..54214f012 100644 --- a/holidays/countries/albania.py +++ b/holidays/countries/albania.py @@ -9,21 +9,20 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import timedelta as td - from holidays.calendars.gregorian import MAR from holidays.calendars.julian import JULIAN_CALENDAR -from holidays.groups import ChristianHolidays, IslamicHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.groups import ChristianHolidays, InternationalHolidays, IslamicHolidays +from holidays.observed_holiday_base import ObservedHolidayBase, SAT_SUN_TO_NEXT_WORKDAY -class Albania(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): +class Albania(ObservedHolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Albania """ country = "AL" + observed_label = "%s (Observed)" special_holidays = { 2022: (MAR, 21, "Public Holiday"), } @@ -32,70 +31,63 @@ def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_WORKDAY, *args, **kwargs) def _populate(self, year): super()._populate(year) - observed_dates = set() + dts_observed = set() # New Year's Day. name = "New Year's Day" - observed_dates.add(self._add_new_years_day(name)) - observed_dates.add(self._add_new_years_day_two(name)) + dts_observed.add(self._add_new_years_day(name)) + dts_observed.add(self._add_new_years_day_two(name)) # Summer Day. if year >= 2004: - observed_dates.add(self._add_holiday_mar_14("Summer Day")) + dts_observed.add(self._add_holiday_mar_14("Summer Day")) # Nevruz. if year >= 1996: - observed_dates.add(self._add_holiday_mar_22("Nevruz")) + dts_observed.add(self._add_holiday_mar_22("Nevruz")) # Easter. - observed_dates.add(self._add_easter_sunday("Catholic Easter")) - observed_dates.add(self._add_easter_sunday("Orthodox Easter", JULIAN_CALENDAR)) + dts_observed.add(self._add_easter_sunday("Catholic Easter")) + dts_observed.add(self._add_easter_sunday("Orthodox Easter", JULIAN_CALENDAR)) # May Day. - observed_dates.add(self._add_labor_day("May Day")) + dts_observed.add(self._add_labor_day("May Day")) # Mother Teresa Day. if 2004 <= year <= 2017: - observed_dates.add(self._add_holiday_oct_19("Mother Teresa Beatification Day")) + dts_observed.add(self._add_holiday_oct_19("Mother Teresa Beatification Day")) elif year >= 2018: - observed_dates.add(self._add_holiday_sep_5("Mother Teresa Canonization Day")) + dts_observed.add(self._add_holiday_sep_5("Mother Teresa Canonization Day")) # Independence Day. - observed_dates.add(self._add_holiday_nov_28("Independence Day")) + dts_observed.add(self._add_holiday_nov_28("Independence Day")) # Liberation Day. - observed_dates.add(self._add_holiday_nov_29("Liberation Day")) + dts_observed.add(self._add_holiday_nov_29("Liberation Day")) # National Youth Day. if year >= 2009: - observed_dates.add(self._add_holiday_dec_8("National Youth Day")) + dts_observed.add(self._add_holiday_dec_8("National Youth Day")) # Christmas Day. - observed_dates.add(self._add_christmas_day("Christmas Day")) + dts_observed.add(self._add_christmas_day("Christmas Day")) # Eid al-Fitr. - observed_dates.update(self._add_eid_al_fitr_day("Eid al-Fitr")) + dts_observed.update(self._add_eid_al_fitr_day("Eid al-Fitr")) # Eid al-Adha. - observed_dates.update(self._add_eid_al_adha_day("Eid al-Adha")) + dts_observed.update(self._add_eid_al_adha_day("Eid al-Adha")) if self.observed: - for dt in sorted(observed_dates): - if not self._is_weekend(dt): - continue - dt_observed = dt + td(days=+1) - while self._is_weekend(dt_observed) or dt_observed in observed_dates: - dt_observed += td(days=+1) - for name in self.get_list(dt): - observed_dates.add(self._add_holiday("%s (Observed)" % name, dt_observed)) - - # observed holidays special cases + self._populate_observed(dts_observed) + + # Observed holidays special cases. if year == 2007: - self._add_holiday_jan_3("Eid al-Adha (Observed)") + self._add_holiday_jan_3(self.observed_label % "Eid al-Adha") class AL(Albania): diff --git a/holidays/countries/algeria.py b/holidays/countries/algeria.py index 0fd29bc9a..458ccbbeb 100644 --- a/holidays/countries/algeria.py +++ b/holidays/countries/algeria.py @@ -25,7 +25,7 @@ class Algeria(HolidayBase, InternationalHolidays, IslamicHolidays): default_language = "ar" # Estimated label. estimated_label = tr("(تقدير*) *%s") - supported_languages = ("ar", "en_US") + supported_languages = ("ar", "en_US", "fr") def __init__(self, *args, **kwargs): InternationalHolidays.__init__(self) @@ -38,43 +38,44 @@ def _populate(self, year): # New Year's Day. self._add_new_years_day(tr("رأس السنة الميلادية")) - # In January 2018, Algeria declared Yennayer a national holiday + # In January 2018, Algeria declared Yennayer a national holiday. if year >= 2018: - # Amazigh New Year / Yennayer + # Amazigh New Year / Yennayer. self._add_holiday_jan_12(tr("رأس السنة الأمازيغية")) - # Labour Day + # Labor Day. self._add_labor_day(tr("عيد العمال")) if year >= 1962: - # Independence Day + # Independence Day. self._add_holiday_jul_5(tr("عيد الإستقلال")) if year >= 1963: - # Revolution Day + # Revolution Day. self._add_holiday_nov_1(tr("عيد الثورة")) - # Islamic New Year + # Islamic New Year. self._add_islamic_new_year_day(tr("رأس السنة الهجرية")) - # Ashura + # Ashura. self._add_ashura_day(tr("عاشورة")) - # Mawlid / Prophet's Birthday + # Mawlid / Prophet's Birthday. self._add_mawlid_day(tr("عيد المولد النبوي")) # As of April 30, 2023. Algeria has 3 days of Eid holidays # (https://www.horizons.dz/english/archives/amp/12021) - # Eid al-Fitr - Feast Festive + + # Eid al-Fitr - Feast Festive. self._add_eid_al_fitr_day(tr("عيد الفطر")) - # Eid al-Fitr Holiday + # Eid al-Fitr Holiday. self._add_eid_al_fitr_day_two(tr("عطلة عيد الفطر")) if year >= 2024: self._add_eid_al_fitr_day_three(tr("عطلة عيد الفطر")) - # Eid al-Adha - Scarfice Festive + # Eid al-Adha - Scarfice Festive. self._add_eid_al_adha_day(tr("عيد الأضحى")) - # Eid al-Adha Holiday + # Eid al-Adha Holiday. self._add_eid_al_adha_day_two(tr("عطلة عيد الأضحى")) if year >= 2023: self._add_eid_al_adha_day_three(tr("عطلة عيد الأضحى")) diff --git a/holidays/countries/angola.py b/holidays/countries/angola.py index 59e2975de..a718eb38b 100644 --- a/holidays/countries/angola.py +++ b/holidays/countries/angola.py @@ -10,15 +10,20 @@ # License: MIT (see LICENSE file) from datetime import date -from datetime import timedelta as td from gettext import gettext as tr +from typing import Tuple from holidays.calendars.gregorian import AUG, SEP, DEC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + TUE_TO_PREV_MON, + THU_TO_NEXT_FRI, + SUN_TO_NEXT_MON, +) -class Angola(HolidayBase, ChristianHolidays, InternationalHolidays): +class Angola(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Angola @@ -38,6 +43,8 @@ class Angola(HolidayBase, ChristianHolidays, InternationalHolidays): country = "AO" default_language = "pt_AO" supported_languages = ("en_US", "pt_AO", "uk") + # %s (Observed). + observed_label = tr("%s (Ponte)") special_holidays = { # General Election Day. 2017: (AUG, 23, tr("Dia de eleições gerais")), @@ -46,23 +53,19 @@ class Angola(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=TUE_TO_PREV_MON + THU_TO_NEXT_FRI, *args, **kwargs) - def _add_observed(self, dt: date) -> None: - if not self.observed: - return None - # As per Law # #11/18, from 2018/9/10, when public holiday falls on Tuesday or Thursday, - # the Monday or Friday is also a holiday. - if dt >= date(2018, SEP, 10): - if self._is_tuesday(dt): - # Day off for %s. - self._add_holiday(self.tr("%s (Ponte)") % self[dt], dt + td(days=-1)) - elif self._is_thursday(dt): - self._add_holiday(self.tr("%s (Ponte)") % self[dt], dt + td(days=+1)) + def _is_observed(self, dt: date) -> bool: # As per Law # 16/96, from 1996/9/27, when public holiday falls on Sunday, # it rolls over to the following Monday. - elif dt >= date(1996, SEP, 27) and self._is_sunday(dt): - self._add_holiday(self.tr("%s (Ponte)") % self[dt], dt + td(days=+1)) + return dt >= date(1996, SEP, 27) + + def _add_observed(self, dt: date, *args) -> Tuple[bool, date]: + # As per Law # #11/18, from 2018/9/10, when public holiday falls on Tuesday or Thursday, + # the Monday or Friday is also a holiday. + return super()._add_observed( + dt, rule=SUN_TO_NEXT_MON if dt < date(2018, SEP, 10) else self._observed_rule + ) def _populate(self, year): # Decree #5/75. @@ -78,7 +81,7 @@ def _populate(self, year): self._add_observed(dt) if self.observed and self._is_monday(DEC, 31) and year >= 2018: - self._add_holiday(self.tr("%s (Ponte)") % name, DEC, 31) + self._add_holiday_dec_31(self.tr(self.observed_label) % name) # Law #16/96. if 1997 <= year <= 2011: diff --git a/holidays/countries/argentina.py b/holidays/countries/argentina.py index 84d2e14bd..af8a4c1b8 100644 --- a/holidays/countries/argentina.py +++ b/holidays/countries/argentina.py @@ -9,30 +9,19 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date from gettext import gettext as tr -from holidays.calendars.gregorian import ( - JAN, - FEB, - MAR, - APR, - MAY, - JUN, - JUL, - AUG, - SEP, - OCT, - NOV, - DEC, - MON, - _get_nth_weekday_from, -) +from holidays.calendars.gregorian import JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + THU_TO_NEXT_MON, + TUE_WED_TO_PREV_MON, + THU_FRI_TO_NEXT_MON, +) -class Argentina(HolidayBase, ChristianHolidays, InternationalHolidays): +class Argentina(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ A subclass of :py:class:`HolidayBase` representing public holidays in Argentina. @@ -69,11 +58,20 @@ class Argentina(HolidayBase, ChristianHolidays, InternationalHolidays): https://servicios.lanacion.com.ar/app-mobile/feriados/2017 https://servicios.lanacion.com.ar/app-mobile/feriados/2016 https://servicios.lanacion.com.ar/app-mobile/feriados/2015 + + Movable Holidays Laws: + - Decreto 1584/2010: 2010-11-03 + - AUG 17, OCT 12, NOV 20 Holidays will always be on MON + - Decreto 52/2017: 2017-01-23 (Reconfirmed in Ley 27399) + - If TUE/WED - observed on previous MON + - If THU/FRI - observed on next MON """ country = "AR" default_language = "es" supported_languages = ("en_US", "es", "uk") + # %s (Observed). + observed_label = tr("%s (Observado)") # Special Bridge Holidays are given upto 3 days a year # as long as it's declared 50 days before calendar year's end @@ -166,27 +164,7 @@ class Argentina(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _move_holiday(self, dt: date) -> None: - """ - Movable Holidays Laws: - - Decreto 1584/2010: 2010-11-03 - - AUG 17, OCT 12, NOV 20 Holidays will always be on MON - - Decreto 52/2017: 2017-01-23 (Reconfirmed in Ley 27399) - - If TUE/WED - observed on previous MON - - If THU/FRI - observed on next MON - """ - if self.observed: - dt_observed = None - if self._is_tuesday(dt) or self._is_wednesday(dt): - dt_observed = _get_nth_weekday_from(-1, MON, dt) - elif self._is_thursday(dt) or self._is_friday(dt): - dt_observed = _get_nth_weekday_from(+1, MON, dt) - - if dt_observed: - self._add_holiday(self.tr("%s (Observado)") % self[dt], dt_observed) - self.pop(dt) + super().__init__(observed_rule=TUE_WED_TO_PREV_MON + THU_FRI_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) @@ -301,8 +279,7 @@ def _populate(self, year): ) # If Jun 17 is Friday, then it should move to Mon, Jun 20 # but Jun 20 is Gen. Belgrano holiday - if not self._is_friday(jun_17): - self._move_holiday(jun_17) + self._move_holiday(jun_17, rule=TUE_WED_TO_PREV_MON + THU_TO_NEXT_MON) # Status: In-Use. # Started in 1938 via Ley 12387 on Aug 17. diff --git a/holidays/countries/australia.py b/holidays/countries/australia.py index 8e6a76d89..bbdac2b2a 100644 --- a/holidays/countries/australia.py +++ b/holidays/countries/australia.py @@ -14,16 +14,22 @@ from holidays.calendars.gregorian import APR, AUG, SEP, OCT, FRI, _get_nth_weekday_from from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + SUN_TO_NEXT_MON, + SAT_SUN_TO_NEXT_MON, + SAT_SUN_TO_NEXT_MON_TUE, +) -class Australia(HolidayBase, ChristianHolidays, InternationalHolidays): +class Australia(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ References: - https://www.qld.gov.au/recreation/travel/holidays """ country = "AU" + observed_label = "%s (Observed)" special_holidays = { 2022: (SEP, 22, "National Day of Mourning for Queen Elizabeth II"), } @@ -41,15 +47,7 @@ def sovereign_birthday(self) -> str: def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, include_sat: bool = True, days: int = +1) -> None: - if not self.observed: - return None - if self._is_sunday(dt) or (include_sat and self._is_saturday(dt)): - self._add_holiday( - "%s (Observed)" % self[dt], dt + td(days=+2 if self._is_saturday(dt) else days) - ) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) @@ -98,11 +96,11 @@ def _add_subdiv_holidays(self): self._add_holiday_apr_25("Anzac Day") # Christmas Day - self._add_observed(self._add_christmas_day("Christmas Day"), days=+2) + self._add_observed(self._add_christmas_day("Christmas Day"), rule=SAT_SUN_TO_NEXT_MON_TUE) # Boxing Day name = "Proclamation Day" if self.subdiv == "SA" else "Boxing Day" - self._add_observed(self._add_christmas_day_two(name), days=+2) + self._add_observed(self._add_christmas_day_two(name), rule=SAT_SUN_TO_NEXT_MON_TUE) super()._add_subdiv_holidays() @@ -120,7 +118,7 @@ def _add_subdiv_act_holidays(self): # Anzac Day if self._year >= 1921: - self._add_observed(date(self._year, APR, 25), include_sat=False) + self._add_observed(date(self._year, APR, 25), rule=SUN_TO_NEXT_MON) # Canberra Day # Info from https://www.timeanddate.com/holidays/australia/canberra-day @@ -217,15 +215,15 @@ def _add_subdiv_qld_holidays(self): # Anzac Day if self._year >= 1921: - self._add_observed(date(self._year, APR, 25), include_sat=False) + self._add_observed((APR, 25), rule=SUN_TO_NEXT_MON) # The Royal Queensland Show (Ekka) # The Show starts on the first Friday of August - providing this is # not prior to the 5th - in which case it will begin on the second # Friday. The Wednesday during the show is a public holiday. ekka_dates = { - 2020: date(2020, AUG, 14), - 2021: date(2021, OCT, 29), + 2020: (AUG, 14), + 2021: (OCT, 29), } name = "The Royal Queensland Show" if self._year in ekka_dates: @@ -248,7 +246,7 @@ def _add_subdiv_sa_holidays(self): # Anzac Day if self._year >= 1921: - self._add_observed(date(self._year, APR, 25), include_sat=False) + self._add_observed((APR, 25), rule=SUN_TO_NEXT_MON) # Adelaide Cup name = "Adelaide Cup" diff --git a/holidays/countries/azerbaijan.py b/holidays/countries/azerbaijan.py index 438961915..18ab57764 100644 --- a/holidays/countries/azerbaijan.py +++ b/holidays/countries/azerbaijan.py @@ -10,48 +10,40 @@ # License: MIT (see LICENSE file) from datetime import date -from datetime import timedelta as td from holidays.calendars import _CustomIslamicCalendar from holidays.calendars.gregorian import JAN, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC from holidays.groups import InternationalHolidays, IslamicHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + WORKDAY_TO_NEXT_WORKDAY, + SAT_SUN_TO_NEXT_WORKDAY, +) -class Azerbaijan(HolidayBase, InternationalHolidays, IslamicHolidays): +class Azerbaijan(ObservedHolidayBase, InternationalHolidays, IslamicHolidays): # [1] https://en.wikipedia.org/wiki/Public_holidays_in_Azerbaijan # [2] https://az.wikipedia.org/wiki/Az%C9%99rbaycan%C4%B1n_d%C3%B6vl%C9%99t_bayramlar%C4%B1_v%C9%99_x%C3%BCsusi_g%C3%BCnl%C9%99ri # noqa: E501 # [3] https://www.sosial.gov.az/en/prod-calendar country = "AZ" + observed_label = "%s (Observed)" def __init__(self, *args, **kwargs): InternationalHolidays.__init__(self) IslamicHolidays.__init__(self, calendar=AzerbaijanIslamicCalendar()) - super().__init__(*args, **kwargs) + super().__init__( + observed_rule=SAT_SUN_TO_NEXT_WORKDAY, observed_since=2006, *args, **kwargs + ) def _populate(self, year): - def _add_observed(dt: date, name: str = None): - """ - Add observed holiday on next working day after specified date. - """ - - next_workday = dt + td(days=+1) - while next_workday in dts_all or self._is_weekend(next_workday): - next_workday += td(days=+1) - if name: - self._add_holiday(f"{name} (Observed)", next_workday) - else: - for h_name in self.get_list(dt): - self._add_holiday(f"{h_name} (Observed)", next_workday) - dts_all.add(next_workday) - if year <= 1989: return None super()._populate(year) dts_observed = set() dts_non_observed = set() + dts_bairami = set() # New Year name = "New Year's Day" @@ -112,47 +104,44 @@ def _add_observed(dt: date, name: str = None): if year >= 1993: solidarity_name = "International Solidarity Day of Azerbaijanis" self._add_new_years_eve(solidarity_name) + self._add_observed(date(year - 1, DEC, 31), name=solidarity_name) if year >= 1993: name = "Ramazan Bayrami" - dts_observed.update(self._add_eid_al_fitr_day(name)) - dts_observed.update(self._add_eid_al_fitr_day_two(name)) + dts_bairami.update(self._add_eid_al_fitr_day(name)) + dts_bairami.update(self._add_eid_al_fitr_day_two(name)) name = "Gurban Bayrami" - dts_observed.update(self._add_eid_al_adha_day(name)) - dts_observed.update(self._add_eid_al_adha_day_two(name)) + dts_bairami.update(self._add_eid_al_adha_day(name)) + dts_bairami.update(self._add_eid_al_adha_day_two(name)) # Article 105 of the Labor Code of the Republic of Azerbaijan states: # 5. If interweekly rest days and holidays that are not considered # working days overlap, that rest day is immediately transferred to # the next working day. if self.observed and year >= 2006: - dts_all = dts_observed.union(dts_non_observed) - - dt = date(year - 1, DEC, 31) - if self._is_weekend(dt): - _add_observed(dt, solidarity_name) - # observed holidays special cases special_dates_obs = {2007: (JAN, 3), 2072: (JAN, 5)} if year in special_dates_obs: - dts_all.add( - self._add_holiday( - "Gurban Bayrami* (*estimated) (Observed)", special_dates_obs[year] - ) + self._add_holiday( + "Gurban Bayrami* (*estimated) (Observed)", special_dates_obs[year] ) - for dt_observed in sorted(dts_observed): - if self._is_weekend(dt_observed): - _add_observed(dt_observed) + self._populate_observed(dts_observed.union(dts_bairami)) + for dt_observed in sorted(dts_bairami.difference(dts_non_observed)): # 6. If the holidays of Qurban and Ramadan coincide with # another holiday that is not considered a working day, # the next working day is considered a rest day. - elif len(self.get_list(dt_observed)) > 1 and dt_observed not in dts_non_observed: - for name in self.get_list(dt_observed): - if "Bayrami" in name: - _add_observed(dt_observed, name) + if len(self.get_list(dt_observed)) == 1: + continue + for name in self.get_list(dt_observed): + if "Bayrami" in name: + self._add_observed( + dt_observed, + name=name, + rule=WORKDAY_TO_NEXT_WORKDAY, + ) class AZ(Azerbaijan): diff --git a/holidays/countries/barbados.py b/holidays/countries/barbados.py index c66c0f43b..9ee77ce42 100644 --- a/holidays/countries/barbados.py +++ b/holidays/countries/barbados.py @@ -9,15 +9,17 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.calendars.gregorian import JAN, JUL from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + MON_TO_NEXT_TUE, + SUN_TO_NEXT_MON, + SUN_TO_NEXT_TUE, +) -class Barbados(HolidayBase, ChristianHolidays, InternationalHolidays): +class Barbados(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://en.wikipedia.org/wiki/Public_holidays_in_Barbados https://www.timeanddate.com/holidays/barbados/ @@ -40,14 +42,10 @@ class Barbados(HolidayBase, ChristianHolidays, InternationalHolidays): 2023: (JUL, 31, "50th Anniversary of CARICOM Holiday"), } - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, days: int = +1) -> None: - if self.observed and self._is_sunday(dt): - self._add_holiday(self.observed_label % self[dt], dt + td(days=days)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): # Public Holidays Act Cap.352, 1968-12-30 @@ -80,10 +78,8 @@ def _populate(self, year): # Emancipation Day name = "Emancipation Day" - self._add_observed(aug_1 := self._add_holiday_aug_1(name), days=+2) - # If Aug 1 is Kadooment Day. - if self.observed and self._is_monday(aug_1): - self._add_holiday(self.observed_label % name, aug_1 + td(days=+1)) + # If Aug 1 is Kadooment Day (i.e. Monday), observed on Tuesday. + self._add_observed(self._add_holiday_aug_1(name), rule=SUN_TO_NEXT_TUE + MON_TO_NEXT_TUE) # Kadooment Day self._add_holiday_1st_mon_of_aug("Kadooment Day") @@ -92,7 +88,7 @@ def _populate(self, year): self._add_observed(self._add_holiday_nov_30("Independence Day")) # Christmas - self._add_observed(self._add_christmas_day("Christmas Day"), days=+2) + self._add_observed(self._add_christmas_day("Christmas Day"), rule=SUN_TO_NEXT_TUE) # Boxing Day self._add_observed(self._add_christmas_day_two("Boxing Day")) diff --git a/holidays/countries/belgium.py b/holidays/countries/belgium.py index 21c2f57dc..cffcb59cd 100644 --- a/holidays/countries/belgium.py +++ b/holidays/countries/belgium.py @@ -9,8 +9,10 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) +from datetime import timedelta as td from gettext import gettext as tr +from holidays.constants import BANK, PUBLIC from holidays.groups import ChristianHolidays, InternationalHolidays from holidays.holiday_base import HolidayBase @@ -20,10 +22,12 @@ class Belgium(HolidayBase, ChristianHolidays, InternationalHolidays): https://en.wikipedia.org/wiki/Public_holidays_in_Belgium https://www.belgium.be/nl/over_belgie/land/belgie_in_een_notendop/feestdagen https://nl.wikipedia.org/wiki/Feestdagen_in_Belgi%C3%AB + https://www.nbb.be/en/about-national-bank/national-bank-belgium/public-holidays """ country = "BE" default_language = "nl" + supported_categories = {BANK, PUBLIC} supported_languages = ("de", "en_US", "fr", "nl", "uk") def __init__(self, *args, **kwargs): @@ -31,9 +35,7 @@ def __init__(self, *args, **kwargs): InternationalHolidays.__init__(self) super().__init__(*args, **kwargs) - def _populate(self, year): - super()._populate(year) - + def _populate_public_holidays(self): # New Year's Day. self._add_new_years_day(tr("Nieuwjaar")) @@ -47,7 +49,7 @@ def _populate(self, year): self._add_labor_day(tr("Dag van de Arbeid")) # Ascension Day. - self._add_ascension_thursday(tr("Hemelvaart")) + self._add_ascension_thursday(tr("O. L. H. Hemelvaart")) # Whit Sunday. self._add_whit_sunday(tr("Pinksteren")) @@ -59,7 +61,7 @@ def _populate(self, year): self._add_holiday_jul_21(tr("Nationale feestdag")) # Assumption of Mary. - self._add_assumption_of_mary_day(tr("Onze Lieve Vrouw hemelvaart")) + self._add_assumption_of_mary_day(tr("O. L. V. Hemelvaart")) # All Saints' Day. self._add_all_saints_day(tr("Allerheiligen")) @@ -70,6 +72,16 @@ def _populate(self, year): # Christmas Day. self._add_christmas_day(tr("Kerstmis")) + def _populate_bank_holidays(self): + # Good Friday. + self._add_good_friday(tr("Goede Vrijdag")) + + # Friday after Ascension Day. + self._add_holiday(tr("Vrijdag na O. L. H. Hemelvaart"), self._easter_sunday + td(days=+40)) + + # Bank Holiday. + self._add_christmas_day_two(tr("Banksluitingsdag")) + class BE(Belgium): pass diff --git a/holidays/countries/belize.py b/holidays/countries/belize.py index 36fee74b6..708cb3ec3 100644 --- a/holidays/countries/belize.py +++ b/holidays/countries/belize.py @@ -9,14 +9,16 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date - -from holidays.calendars.gregorian import MON, _get_nth_weekday_from from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + SUN_TO_NEXT_MON, + TUE_WED_THU_TO_PREV_MON, + FRI_SUN_TO_NEXT_MON, +) -class Belize(HolidayBase, ChristianHolidays, InternationalHolidays): +class Belize(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Belize @@ -26,33 +28,16 @@ class Belize(HolidayBase, ChristianHolidays, InternationalHolidays): """ country = "BZ" + observed_label = "%s (Observed)" - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _move_holiday(self, dt: date, sunday_only: bool = True) -> None: # Chapter 289 of the laws of Belize states that if the holiday falls # on a Sunday or a Friday, the following Monday is observed as public # holiday; further, if the holiday falls on a Tuesday, Wednesday or # Thursday, the preceding Monday is observed as public holiday - if not self.observed: - return None - - dt_observed = None - if sunday_only: - if self._is_sunday(dt): - dt_observed = _get_nth_weekday_from(+1, MON, dt) - else: - if self._is_friday(dt) or self._is_sunday(dt): - dt_observed = _get_nth_weekday_from(+1, MON, dt) - elif self._is_tuesday(dt) or self._is_wednesday(dt) or self._is_thursday(dt): - dt_observed = _get_nth_weekday_from(-1, MON, dt) - - if dt_observed: - self._add_holiday("%s (Observed)" % self[dt], dt_observed) - self.pop(dt) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): # Belize was granted independence on 21.09.1981. @@ -69,7 +54,8 @@ def _populate(self, year): # National Heroes and Benefactors Day. self._move_holiday( - self._add_holiday_mar_9("National Heroes and Benefactors Day"), sunday_only=False + self._add_holiday_mar_9("National Heroes and Benefactors Day"), + rule=TUE_WED_THU_TO_PREV_MON + FRI_SUN_TO_NEXT_MON, ) # Good Friday. @@ -86,11 +72,17 @@ def _populate(self, year): if year <= 2021: # Commonwealth Day. - self._move_holiday(self._add_holiday_may_24("Commonwealth Day"), sunday_only=False) + self._move_holiday( + self._add_holiday_may_24("Commonwealth Day"), + rule=TUE_WED_THU_TO_PREV_MON + FRI_SUN_TO_NEXT_MON, + ) if year >= 2021: # Emancipation Day. - self._move_holiday(self._add_holiday_aug_1("Emancipation Day"), sunday_only=False) + self._move_holiday( + self._add_holiday_aug_1("Emancipation Day"), + rule=TUE_WED_THU_TO_PREV_MON + FRI_SUN_TO_NEXT_MON, + ) # Saint George's Caye Day. self._move_holiday(self._add_holiday_sep_10("Saint George's Caye Day")) @@ -100,7 +92,9 @@ def _populate(self, year): # Indigenous Peoples' Resistance Day / Pan American Day. name = "Indigenous Peoples' Resistance Day" if year >= 2021 else "Pan American Day" - self._move_holiday(self._add_columbus_day(name), sunday_only=False) + self._move_holiday( + self._add_columbus_day(name), rule=TUE_WED_THU_TO_PREV_MON + FRI_SUN_TO_NEXT_MON + ) # Garifuna Settlement Day. self._move_holiday(self._add_holiday_nov_19("Garifuna Settlement Day")) diff --git a/holidays/countries/bolivia.py b/holidays/countries/bolivia.py index a1435fe10..42ae9ce34 100644 --- a/holidays/countries/bolivia.py +++ b/holidays/countries/bolivia.py @@ -10,15 +10,19 @@ # License: MIT (see LICENSE file) # Copyright: Kateryna Golovanova , 2022 -from datetime import date from datetime import timedelta as td from gettext import gettext as tr from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + TUE_TO_PREV_MON, + THU_TO_NEXT_FRI, + SUN_TO_NEXT_MON, +) -class Bolivia(HolidayBase, ChristianHolidays, InternationalHolidays): +class Bolivia(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ References: - [Supreme Decree #14260] https://bolivia.infoleyes.com/norma/1141/decreto-supremo-14260 @@ -49,17 +53,11 @@ class Bolivia(HolidayBase, ChristianHolidays, InternationalHolidays): "T", # Tarija ) - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date) -> None: # Supreme Decree #14260. - # whenever a public holiday falls on a Sunday, - # it rolls over to the following Monday. - if self.observed and self._year >= 1977 and self._is_sunday(dt): - self._add_holiday(self.tr(self.observed_label) % self[dt], dt + td(days=+1)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, observed_since=1977, *args, **kwargs) def _populate(self, year): if year <= 1824: @@ -88,15 +86,10 @@ def _populate(self, year): self._add_good_friday(tr("Viernes Santo")) # Labor Day. - name = self.tr("Día del Trabajo") - may_1 = self._add_labor_day(name) - self._add_observed(may_1) + self._add_observed(may_1 := self._add_labor_day(self.tr("Día del Trabajo"))) # Supreme Decree #1210. - if self.observed and 2012 <= year <= 2015: - if self._is_tuesday(may_1): - self._add_holiday(self.tr(self.observed_label) % name, may_1 + td(days=-1)) - elif self._is_thursday(may_1): - self._add_holiday(self.tr(self.observed_label) % name, may_1 + td(days=+1)) + if 2012 <= year <= 2015: + self._add_observed(may_1, rule=TUE_TO_PREV_MON + THU_TO_NEXT_FRI) # Corpus Christi. self._add_corpus_christi_day(tr("Corpus Christi")) diff --git a/holidays/countries/bosnia_and_herzegovina.py b/holidays/countries/bosnia_and_herzegovina.py index 1ce97690f..d9e310047 100644 --- a/holidays/countries/bosnia_and_herzegovina.py +++ b/holidays/countries/bosnia_and_herzegovina.py @@ -10,8 +10,6 @@ # License: MIT (see LICENSE file) # Copyright: Kateryna Golovanova , 2022 -from datetime import date -from datetime import timedelta as td from gettext import gettext as tr from holidays.calendars import _CustomIslamicCalendar @@ -32,20 +30,35 @@ ) from holidays.calendars.julian import JULIAN_CALENDAR from holidays.groups import ChristianHolidays, IslamicHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + SAT_TO_NEXT_MON, + SUN_TO_NEXT_MON, + SUN_TO_NEXT_TUE, + SAT_SUN_TO_NEXT_MON_TUE, +) -class BosniaAndHerzegovina(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): +class BosniaAndHerzegovina( + ObservedHolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays +): """ https://en.wikipedia.org/wiki/Public_holidays_in_Bosnia_and_Herzegovina https://www.paragraf.ba/neradni-dani-fbih.html https://www.paragraf.ba/neradni-dani-republike-srpske.html https://www.paragraf.ba/neradni-dani-brcko.html + + Observed holidays rules: + - BIH: if first day of New Year's Day and Labor Day fall on Sunday, observed on Tuesday. + - BRC: if holiday fall on Sunday, observed on next working day. + - SRP: if second day of New Year's Day and Labor Day fall on Sunday, observed on Monday. """ country = "BA" default_language = "bs" supported_languages = ("bs", "en_US", "sr", "uk") + # %s (Observed). + observed_label = tr("%s (preneseno)") subdivisions = ( "BIH", # Federacija Bosne i Hercegovine "BRC", # Brčko distrikt @@ -61,21 +74,7 @@ def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self, JULIAN_CALENDAR) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self, calendar=BosniaAndHerzegovinaIslamicCalendar()) - super().__init__(*args, **kwargs) - - def _add_observed( - self, dt: date, include_sat: bool = True, include_sun: bool = True, days: int = +1 - ) -> None: - # BIH: if first day of New Year's Day and Labor Day fall on Sunday, observed on Tuesday. - # BRC: if holiday fall on Sunday, observed on next working day. - # SRP: if second day of New Year's Day and Labor Day fall on Sunday, observed on Monday. - if not self.observed: - return None - if (include_sun and self._is_sunday(dt)) or (include_sat and self._is_saturday(dt)): - self._add_holiday( - self.tr("%s (preneseno)") % self[dt], - dt + td(days=+2 if self._is_saturday(dt) else days), - ) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) @@ -122,7 +121,7 @@ def _add_subdiv_holidays(self): def _add_subdiv_bih_holidays(self): # New Year's Day. name = tr("Nova godina") - self._add_observed(self._add_new_years_day(name), include_sat=False, days=+2) + self._add_observed(self._add_new_years_day(name), rule=SUN_TO_NEXT_TUE) self._add_new_years_day_two(name) # Orthodox Christmas Eve. @@ -148,7 +147,7 @@ def _add_subdiv_bih_holidays(self): # Labor Day. name = tr("Međunarodni praznik rada") - self._add_observed(self._add_labor_day(name), include_sat=False, days=+2) + self._add_observed(self._add_labor_day(name), rule=SUN_TO_NEXT_TUE) self._add_labor_day_two(name) # Victory Day. @@ -172,36 +171,31 @@ def _add_subdiv_bih_holidays(self): def _add_subdiv_brc_holidays(self): # New Year's Day. name = tr("Nova godina") - self._add_observed(self._add_new_years_day(name), days=+2) + self._add_observed(self._add_new_years_day(name), rule=SAT_SUN_TO_NEXT_MON_TUE) self._add_new_years_day_two(name) # Orthodox Christmas. - self._add_observed( - self._add_christmas_day(tr("Božić (Pravoslavni)")), - include_sat=False, - ) + self._add_observed(self._add_christmas_day(tr("Božić (Pravoslavni)"))) self._add_observed( # Day of establishment of Brčko District. - self._add_holiday_mar_8(tr("Dan uspostavljanja Brčko distrikta")), - include_sat=False, + self._add_holiday_mar_8(tr("Dan uspostavljanja Brčko distrikta")) ) # Labor Day. name = tr("Međunarodni praznik rada") - self._add_observed(self._add_labor_day(name), days=+2) + self._add_observed(self._add_labor_day(name), rule=SAT_SUN_TO_NEXT_MON_TUE) self._add_labor_day_two(name) self._add_observed( # Catholic Christmas. - self._add_christmas_day(tr("Božić (Katolički)"), GREGORIAN_CALENDAR), - include_sat=False, + self._add_christmas_day(tr("Božić (Katolički)"), GREGORIAN_CALENDAR) ) def _add_subdiv_srp_holidays(self): # New Year's Day. name = tr("Nova godina") - self._add_observed(self._add_new_years_day(name), include_sun=False) + self._add_observed(self._add_new_years_day(name), rule=SAT_TO_NEXT_MON) self._add_new_years_day_two(name) # Orthodox Christmas Eve. @@ -227,7 +221,7 @@ def _add_subdiv_srp_holidays(self): # Labor Day. name = tr("Međunarodni praznik rada") - self._add_observed(self._add_labor_day(name), include_sun=False) + self._add_observed(self._add_labor_day(name), rule=SAT_TO_NEXT_MON) self._add_labor_day_two(name) # Victory Day. diff --git a/holidays/countries/botswana.py b/holidays/countries/botswana.py index 88e068822..4868b5319 100644 --- a/holidays/countries/botswana.py +++ b/holidays/countries/botswana.py @@ -9,15 +9,14 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date from datetime import timedelta as td from holidays.calendars.gregorian import JUL from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON, SUN_TO_NEXT_TUE -class Botswana(HolidayBase, ChristianHolidays, InternationalHolidays): +class Botswana(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://www.gov.bw/public-holidays https://publicholidays.africa/botswana/2021-dates/ @@ -26,16 +25,13 @@ class Botswana(HolidayBase, ChristianHolidays, InternationalHolidays): """ country = "BW" + observed_label = "%s (Observed)" special_holidays = {2019: (JUL, 2, "Public Holiday")} - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, days: int = +1) -> None: - if self.observed and self._is_sunday(dt) and self._year >= 1995: - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=days)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, observed_since=1995, *args, **kwargs) def _populate(self, year): if year <= 1965: @@ -43,7 +39,7 @@ def _populate(self, year): super()._populate(year) - self._add_observed(self._add_new_years_day("New Year's Day"), days=+2) + self._add_observed(self._add_new_years_day("New Year's Day"), rule=SUN_TO_NEXT_TUE) self._add_observed(self._add_new_years_day_two("New Year's Day Holiday")) # Easter and easter related calculations @@ -63,12 +59,11 @@ def _populate(self, year): self._add_holiday("President's Day Holiday", third_mon_of_jul + td(days=+1)) sep_30 = self._add_holiday_sep_30("Botswana Day") - self._add_observed(sep_30, days=+2) + self._add_observed(sep_30, rule=SUN_TO_NEXT_TUE) self._add_observed(self._add_holiday("Botswana Day Holiday", sep_30 + td(days=+1))) - self._add_observed(self._add_christmas_day("Christmas Day"), days=+2) - dec_26 = self._add_christmas_day_two("Boxing Day") - self._add_observed(dec_26) + self._add_observed(self._add_christmas_day("Christmas Day"), rule=SUN_TO_NEXT_TUE) + self._add_observed(dec_26 := self._add_christmas_day_two("Boxing Day")) if self.observed and year >= 2016 and self._is_saturday(dec_26): self._add_holiday("Boxing Day Holiday", dec_26 + td(days=+2)) diff --git a/holidays/countries/brazil.py b/holidays/countries/brazil.py index c117ffbef..6768b5fa4 100644 --- a/holidays/countries/brazil.py +++ b/holidays/countries/brazil.py @@ -13,6 +13,7 @@ from datetime import date from holidays.calendars.gregorian import JAN, MAR, SEP, NOV, FRI, _get_nth_weekday_from +from holidays.constants import OPTIONAL, PUBLIC from holidays.groups import ChristianHolidays, InternationalHolidays from holidays.holiday_base import HolidayBase @@ -57,37 +58,37 @@ class Brazil(HolidayBase, ChristianHolidays, InternationalHolidays): "SP", # São Paulo "TO", # Tocantins ) + supported_categories = {OPTIONAL, PUBLIC} def __init__(self, *args, **kwargs) -> None: ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) super().__init__(*args, **kwargs) - def _populate(self, year): + def _populate_public_holidays(self): # Decreto n. 155-B, de 14.01.1890 - if year <= 1889: + if self._year <= 1889: return None - super()._populate(year) # New Year's Day. self._add_new_years_day("Confraternização Universal") - if 1892 <= year <= 1930: + if 1892 <= self._year <= 1930: # Republic Constitution Day. self._add_holiday_feb_24("Constituição da Republica") # Good Friday. self._add_good_friday("Sexta-feira Santa") - if year not in {1931, 1932}: + if self._year not in {1931, 1932}: # Tiradentes' Day. self._add_holiday_apr_21("Tiradentes") - if year >= 1925: + if self._year >= 1925: # Labor Day. self._add_labor_day("Dia do Trabalhador") - if year <= 1930: + if self._year <= 1930: # Discovery of Brazil. self._add_holiday_may_3("Descobrimento do Brasil") @@ -100,7 +101,7 @@ def _populate(self, year): # Independence Day. self._add_holiday_sep_7("Independência do Brasil") - if year <= 1930 or year >= 1980: + if self._year <= 1930 or self._year >= 1980: # Our Lady of Aparecida. self._add_holiday_oct_12("Nossa Senhora Aparecida") @@ -110,11 +111,13 @@ def _populate(self, year): # Republic Proclamation Day. self._add_holiday_nov_15("Proclamação da República") - if year >= 1922: + if self._year >= 1922: # Christmas Day. self._add_christmas_day("Natal") - # Optional holidays + def _populate_optional_holidays(self): + if self._year <= 1889: + return None # Carnival. self._add_carnival_monday("Carnaval") diff --git a/holidays/countries/brunei.py b/holidays/countries/brunei.py index 8c6ca9f79..e93d98260 100644 --- a/holidays/countries/brunei.py +++ b/holidays/countries/brunei.py @@ -9,8 +9,6 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td from gettext import gettext as tr from holidays.calendars import _CustomIslamicCalendar @@ -21,11 +19,22 @@ InternationalHolidays, IslamicHolidays, ) -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + FRI_TO_NEXT_MON, + FRI_TO_NEXT_SAT, + SUN_TO_NEXT_TUE, + SUN_TO_NEXT_WED, + FRI_SUN_TO_NEXT_SAT_MON, +) class Brunei( - HolidayBase, ChineseCalendarHolidays, ChristianHolidays, InternationalHolidays, IslamicHolidays + ObservedHolidayBase, + ChineseCalendarHolidays, + ChristianHolidays, + InternationalHolidays, + IslamicHolidays, ): """ A subclass of :py:class:`HolidayBase` representing public holidays in Brunei Darussalam. @@ -40,6 +49,9 @@ class Brunei( - [Jubli Emas Sultan Hassanal Bolkiah] https://www.brudirect.com/news.php?id=28316 + If Public Holiday falls on either Friday or Sunday, in-lieu observance is given out + on the following Saturday or Monday. + Limitations: - Brunei Darussalam holidays only works from 1984 onwards @@ -54,6 +66,7 @@ class Brunei( country = "BN" default_language = "ms" estimated_label = tr("%s* (*anggaran)") + observed_label = tr("%s - Diperhatikan") supported_languages = ("en_US", "ms", "th") special_holidays = { @@ -66,50 +79,40 @@ def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self, calendar=BruneiIslamicCalendar()) - - super().__init__(*args, **kwargs) + super().__init__(observed_rule=FRI_SUN_TO_NEXT_SAT_MON, *args, **kwargs) def _populate(self, year): # Available post-Independence from 1984 afterwards if year <= 1983: return None - def _add_observed(dt: date) -> None: - """ - If Public Holiday falls on either Friday or Sunday, in-lieu - observance is given out on the following Saturday or Monday. - """ - if self.observed and (self._is_friday(dt) or self._is_sunday(dt)): - for name in self.get_list(dt): - self._add_holiday(self.tr("%s - Diperhatikan") % name, dt + td(days=+1)) - super()._populate(year) # Awal Tahun Masihi # Status: In-Use. # New Year's Day - _add_observed(self._add_new_years_day(tr("Awal Tahun Masihi"))) + self._add_observed(self._add_new_years_day(tr("Awal Tahun Masihi"))) # Tahun Baru Cina # Status: In-Use. # Lunar New Year - _add_observed(self._add_chinese_new_years_day(tr("Tahun Baru Cina"))) + self._add_observed(self._add_chinese_new_years_day(tr("Tahun Baru Cina"))) # Hari Kebangsaan # Status: In-Use. # Starts in 1984. # National Day - _add_observed(self._add_holiday_feb_23(tr("Hari Kebangsaan"))) + self._add_observed(self._add_holiday_feb_23(tr("Hari Kebangsaan"))) # Hari Angkatan Bersenjata Diraja Brunei # Status: In-Use. # Starts in 1984. # Commemorates the formation of Royal Brunei Malay Regiment in 1961. - _add_observed( + self._add_observed( # Armed Forces Day self._add_holiday_may_31(tr("Hari Angkatan Bersenjata Diraja Brunei")) ) @@ -118,7 +121,7 @@ def _add_observed(dt: date) -> None: # Status: In-Use. # Started in 1968. - _add_observed( + self._add_observed( # Sultan Hassanal Bolkiah's Birthday self._add_holiday_jul_15(tr("Hari Keputeraan KDYMM Sultan Brunei")) ) @@ -127,7 +130,7 @@ def _add_observed(dt: date) -> None: # Status: In-Use. # Christmas Day - _add_observed(self._add_christmas_day(tr("Hari Natal"))) + self._add_observed(self._add_christmas_day(tr("Hari Natal"))) # Islamic Holidays are placed after Gregorian holidays to prevent # the duplication of observed tags. - see #1168 @@ -137,76 +140,61 @@ def _add_observed(dt: date) -> None: # Isra Mi'raj for dt in self._add_isra_and_miraj_day(tr("Israk dan Mikraj")): - _add_observed(dt) + self._add_observed(dt) # Hari Pertama Berpuasa # Status: In-Use. # First Day of Ramadan for dt in self._add_ramadan_beginning_day(tr("Hari Pertama Berpuasa")): - _add_observed(dt) + self._add_observed(dt) # Hari Nuzul Al-Quran # Status: In-Use. # Anniversary of the revelation of the Quran for dt in self._add_nuzul_al_quran_day(tr("Hari Nuzul Al-Quran")): - _add_observed(dt) + self._add_observed(dt) # Hari Raya Aidil Fitri # Status: In-Use. # This is celebrate for three days in Brunei. # Observed as 'Hari Raya Puasa' and only for 2 days at certain point. - # We utilizes a separate in-lieu trigger for this one. - # 1: If Wed-Thu-Fri -> Sat (+3) - # 2: If Thu-Fri-Sat -> Mon (+4) - # 3: If Fri-Sat-Sun -> Mon (+3) - # 4: If Sat-Sun-Mon -> Tue (+3) - # 5: If Sun-Mon-Tue -> Wed (+3) + # 1: If Wed-Thu-Fri -> Sat (3rd Day +1) + # 2: If Thu-Fri-Sat -> Mon (2nd Day +3) + # 3: If Fri-Sat-Sun -> Mon (1st Day +3) + # 4: If Sat-Sun-Mon -> Tue (2nd Day +2) + # 5: If Sun-Mon-Tue -> Wed (1st Day +3) # Eid al-Fitr name = tr("Hari Raya Aidil Fitri") - - al_fitr_dates = self._add_eid_al_fitr_day(name) - self._add_eid_al_fitr_day_two(name) - self._add_eid_al_fitr_day_three(name) - - if self.observed: - for dt in al_fitr_dates: - dt_observed = None - for delta in range(3): - dt_delta = dt + td(days=delta) - if self._is_friday(dt_delta) or self._is_sunday(dt_delta): - dt_observed = dt + td(days=+3) - if self._is_sunday(dt_observed): - dt_observed += td(days=+1) - break - if dt_observed: - self._add_islamic_calendar_holiday( - self.tr("%s - Diperhatikan") % self[dt_delta], - ((dt_observed, year not in BruneiIslamicCalendar.EID_AL_FITR_DATES),), - ) + for dt in self._add_eid_al_fitr_day(name): + self._add_observed(dt, rule=FRI_TO_NEXT_MON + SUN_TO_NEXT_WED) + for dt in self._add_eid_al_fitr_day_two(name): + self._add_observed(dt, rule=FRI_TO_NEXT_MON + SUN_TO_NEXT_TUE) + for dt in self._add_eid_al_fitr_day_three(name): + self._add_observed(dt, rule=FRI_TO_NEXT_SAT) # Hari Raya Aidil Adha # Status: In-Use. # Eid al-Adha for dt in self._add_eid_al_adha_day(tr("Hari Raya Aidil Adha")): - _add_observed(dt) + self._add_observed(dt) # Awal Tahun Hijrah # Status: In-Use. # Islamic New Year for dt in self._add_islamic_new_year_day(tr("Awal Tahun Hijrah")): - _add_observed(dt) + self._add_observed(dt) # Maulidur Rasul # Status: In-Use. # Birth of the Prophet for dt in self._add_mawlid_day(tr("Maulidur Rasul")): - _add_observed(dt) + self._add_observed(dt) class BN(Brunei): diff --git a/holidays/countries/bulgaria.py b/holidays/countries/bulgaria.py index 1a713ab46..8bb2fb0fc 100644 --- a/holidays/countries/bulgaria.py +++ b/holidays/countries/bulgaria.py @@ -9,16 +9,17 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import timedelta as td +from datetime import date from gettext import gettext as tr +from typing import Set from holidays.calendars.julian_revised import JULIAN_REVISED_CALENDAR from holidays.constants import PUBLIC, SCHOOL from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SAT_SUN_TO_NEXT_WORKDAY -class Bulgaria(HolidayBase, ChristianHolidays, InternationalHolidays): +class Bulgaria(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ Official holidays in Bulgaria in their current form. This class does not any return holidays before 1990, as holidays in the People's Republic of @@ -43,13 +44,25 @@ class Bulgaria(HolidayBase, ChristianHolidays, InternationalHolidays): country = "BG" default_language = "bg" + # %s (Observed). + observed_label = tr("%s (почивен ден)") supported_categories = {PUBLIC, SCHOOL} supported_languages = ("bg", "en_US", "uk") def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self, JULIAN_REVISED_CALENDAR) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__( + observed_rule=SAT_SUN_TO_NEXT_WORKDAY, observed_since=2017, *args, **kwargs + ) + + def _populate_observed(self, dts: Set[date], excluded_names: Set[str]) -> None: + for dt in sorted(dts): + if not self._is_observed(dt): + continue + for name in self.get_list(dt): + if name not in excluded_names: + self._add_observed(dt, name) def _populate_public_holidays(self): if self._year <= 1989: @@ -110,19 +123,15 @@ def _populate_public_holidays(self): dts_observed.add(self._add_christmas_day(name)) dts_observed.add(self._add_christmas_day_two(name)) - if self.observed and self._year >= 2017: - excluded_names = {self.tr("Велика събота"), self.tr("Великден")} - for dt in sorted(dts_observed): - if not self._is_weekend(dt): - continue - dt_observed = dt + td(days=+2 if self._is_saturday(dt) else +1) - while dt_observed in self: - dt_observed += td(days=+1) - for name in self.get_list(dt): - if name not in excluded_names: - self._add_holiday(self.tr("%s (почивен ден)") % name, dt_observed) + if self.observed: + self._populate_observed( + dts_observed, excluded_names={self.tr("Велика събота"), self.tr("Великден")} + ) def _populate_school_holidays(self): + if self._year <= 1989: + return None + # National Awakening Day. self._add_holiday_nov_1(tr("Ден на народните будители")) diff --git a/holidays/countries/burkina_faso.py b/holidays/countries/burkina_faso.py index a76ac669d..bfcf3ee8e 100644 --- a/holidays/countries/burkina_faso.py +++ b/holidays/countries/burkina_faso.py @@ -9,32 +9,26 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.calendars import _CustomIslamicCalendar from holidays.calendars.gregorian import JAN, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC from holidays.groups import ChristianHolidays, InternationalHolidays, IslamicHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class BurkinaFaso(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): +class BurkinaFaso(ObservedHolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Burkina_Faso """ country = "BF" + observed_label = "%s (Observed)" - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self, calendar=BurkinaFasoIslamicCalendar()) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date) -> None: - if self.observed and self._is_sunday(dt): - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=+1)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): # On 5 August 1960, Burkina Faso (Republic of Upper Volta at that time) diff --git a/holidays/countries/burundi.py b/holidays/countries/burundi.py index 6429c0c7c..b541716d0 100644 --- a/holidays/countries/burundi.py +++ b/holidays/countries/burundi.py @@ -9,15 +9,11 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td -from typing import Optional - from holidays.groups import ChristianHolidays, IslamicHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class Burundi(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): +class Burundi(ObservedHolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): """ Burundian holidays Note that holidays falling on a sunday maybe observed @@ -30,22 +26,13 @@ class Burundi(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHoli """ country = "BI" + observed_label = "%s (Observed)" def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_holiday(self, name: str, *args) -> Optional[date]: - dt = args if len(args) > 1 else args[0] - dt = dt if isinstance(dt, date) else date(self._year, *dt) - - dt_added = super()._add_holiday(name, dt) - if self.observed and dt_added and self._is_sunday(dt_added): - dt_added = super()._add_holiday("%s (Observed)" % self[dt], dt + td(days=+1)) - - return dt_added + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): if year <= 1961: @@ -54,52 +41,52 @@ def _populate(self, year): super()._populate(year) # New Year's Day - self._add_new_years_day("New Year's Day") + self._add_observed(self._add_new_years_day("New Year's Day")) # Unity Day if year >= 1992: - self._add_holiday_feb_5("Unity Day") + self._add_observed(self._add_holiday_feb_5("Unity Day")) # President Ntaryamira Day if year >= 1995: - self._add_holiday_apr_6("President Ntaryamira Day") + self._add_observed(self._add_holiday_apr_6("President Ntaryamira Day")) # Labour Day - self._add_labor_day("Labour Day") + self._add_observed(self._add_labor_day("Labour Day")) # Ascension Day self._add_ascension_thursday("Ascension Day") # President Nkurunziza Day if year >= 2022: - self._add_holiday_jun_8("President Nkurunziza Day") + self._add_observed(self._add_holiday_jun_8("President Nkurunziza Day")) # Independence Day - self._add_holiday_jul_1("Independence Day") + self._add_observed(self._add_holiday_jul_1("Independence Day")) # Assumption Day - self._add_assumption_of_mary_day("Assumption Day") + self._add_observed(self._add_assumption_of_mary_day("Assumption Day")) # Prince Louis Rwagasore Day - self._add_holiday_oct_13("Prince Louis Rwagasore Day") + self._add_observed(self._add_holiday_oct_13("Prince Louis Rwagasore Day")) # President Ndadaye's Day if year >= 1994: - self._add_holiday_oct_21("President Ndadaye's Day") + self._add_observed(self._add_holiday_oct_21("President Ndadaye's Day")) # All Saints' Day - self._add_all_saints_day("All Saints' Day") + self._add_observed(self._add_all_saints_day("All Saints' Day")) # Christmas Day - self._add_christmas_day("Christmas Day") + self._add_observed(self._add_christmas_day("Christmas Day")) # Eid ul Fitr - # date of observance is announced yearly - self._add_eid_al_fitr_day("Eid ul Fitr") + for dt in self._add_eid_al_fitr_day("Eid ul Fitr"): + self._add_observed(dt) # Eid al Adha - # date of observance is announced yearly - self._add_eid_al_adha_day("Eid al Adha") + for dt in self._add_eid_al_adha_day("Eid al Adha"): + self._add_observed(dt) class BI(Burundi): diff --git a/holidays/countries/cameroon.py b/holidays/countries/cameroon.py index cfdbef817..d83bcd7e7 100644 --- a/holidays/countries/cameroon.py +++ b/holidays/countries/cameroon.py @@ -9,15 +9,13 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import timedelta as td - from holidays.calendars import _CustomIslamicCalendar from holidays.calendars.gregorian import JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC from holidays.groups import ChristianHolidays, InternationalHolidays, IslamicHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_WORKDAY -class Cameroon(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): +class Cameroon(ObservedHolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Cameroon @@ -26,6 +24,7 @@ class Cameroon(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHol """ country = "CM" + observed_label = "%s (Observed)" special_holidays = { 2021: ( (MAY, 14, "Public Holiday"), @@ -33,11 +32,11 @@ class Cameroon(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHol ), } - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self, calendar=CameroonIslamicCalendar()) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=SUN_TO_NEXT_WORKDAY, *args, **kwargs) def _populate(self, year): # On 1 January 1960, French Cameroun gained independence from France. @@ -83,18 +82,11 @@ def _populate(self, year): dts_observed.update(self._add_mawlid_day("Mawlid")) if self.observed: - for dt in sorted(dts_observed): - if not self._is_sunday(dt): - continue - dt_observed = dt + td(days=+1) - while dt_observed in dts_observed: - dt_observed += td(days=+1) - for name in self.get_list(dt): - dts_observed.add(self._add_holiday("%s (Observed)" % name, dt_observed)) + self._populate_observed(dts_observed) # Observed holidays special cases. if year == 2007: - self._add_holiday_jan_2("Eid al-Adha (Observed)") + self._add_holiday_jan_2(self.observed_label % "Eid al-Adha") class CM(Cameroon): diff --git a/holidays/countries/canada.py b/holidays/countries/canada.py index 37539ed03..92dd56e47 100644 --- a/holidays/countries/canada.py +++ b/holidays/countries/canada.py @@ -10,17 +10,40 @@ # License: MIT (see LICENSE file) from datetime import date -from datetime import timedelta as td from gettext import gettext as tr -from holidays.calendars.gregorian import MAR, APR, JUN, JUL, MON, _get_nth_weekday_from +from holidays.calendars.gregorian import MAR, APR, JUN, JUL +from holidays.constants import GOVERNMENT, OPTIONAL, PUBLIC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + ALL_TO_NEAREST_MON, + SAT_SUN_TO_NEXT_MON, + SAT_SUN_TO_NEXT_MON_TUE, + SUN_TO_NEXT_MON, + SUN_TO_NEXT_TUE, +) + + +class Canada(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): + """ + References: + - https://en.wikipedia.org/wiki/Public_holidays_in_Canada + - https://web.archive.org/web/20130703014214/http://www.hrsdc.gc.ca/eng/labour/overviews/employment_standards/holidays.shtml # noqa: E501 + - https://www.alberta.ca/alberta-general-holidays + - https://www2.gov.bc.ca/gov/content/employment-business/employment-standards-advice/employment-standards/statutory-holidays # noqa: E501 + - http://web2.gov.mb.ca/laws/statutes/ccsm/r120e.php + - https://www2.gnb.ca/content/gnb/en/departments/elg/local_government/content/governance/content/days_of_rest_act.html # noqa: E501 + - https://www.ontario.ca/document/your-guide-employment-standards-act-0/public-holidays + - https://www.officeholidays.com/countries/canada/ + - https://www.timeanddate.com/holidays/canada/ + """ - -class Canada(HolidayBase, ChristianHolidays, InternationalHolidays): country = "CA" default_language = "en" + # %s (Observed). + observed_label = tr("%s (Observed)") + supported_categories = {GOVERNMENT, OPTIONAL, PUBLIC} subdivisions = ( "AB", "BC", @@ -39,66 +62,98 @@ class Canada(HolidayBase, ChristianHolidays, InternationalHolidays): supported_languages = ("ar", "en", "fr", "th") def __init__(self, *args, **kwargs): - # Default subdivision to ON; prov for backwards compatibility - if not kwargs.get("subdiv", kwargs.get("prov")): - kwargs["subdiv"] = "ON" ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_MON, *args, **kwargs) def _get_nearest_monday(self, *args) -> date: - dt = date(self._year, *args) - return _get_nth_weekday_from( - +1 if self._is_friday(dt) or self._is_weekend(dt) else -1, - MON, - dt, - ) - - def _add_observed(self, dt: date, include_sat: bool = True, days: int = +1) -> None: - if not self.observed: - return None - if self._is_sunday(dt) or (include_sat and self._is_saturday(dt)): - self._add_holiday( - self.tr("%s (Observed)") % self[dt], - dt + td(days=+2 if self._is_saturday(dt) else days), - ) + return self._get_observed_date(date(self._year, *args), rule=ALL_TO_NEAREST_MON) - def _populate(self, year): - if year <= 1866: - return None - - super()._populate(year) + def _add_common_holidays(self): + """Nationwide statutory holidays.""" # New Year's Day. self._add_observed(self._add_new_years_day(tr("New Year's Day"))) # Good Friday. self._add_good_friday(tr("Good Friday")) - # Easter Monday. - self._add_easter_monday(tr("Easter Monday")) - if year <= 1982: - # Dominion Day. - self._add_observed(self._add_holiday_jul_1(tr("Dominion Day"))) + if self._year >= 1879: + self._canada_day = self._add_holiday_jul_1( + # Canada Day. + tr("Canada Day") + if self._year >= 1983 + # Dominion Day. + else tr("Dominion Day") + ) if self._year >= 1894: # Labour Day. self._add_holiday_1st_mon_of_sep(tr("Labour Day")) # Christmas Day. - self._add_observed(self._add_christmas_day(tr("Christmas Day")), days=+2) + self._add_christmas_day(tr("Christmas Day")) + + def _populate_public_holidays(self): + if self._year <= 1866: + return None + + self._add_common_holidays() + + self._add_observed(self._christmas_day) + + def _populate_government_holidays(self): + """Holidays for federally regulated workplaces.""" + + if self._year <= 1866: + return None + + self._add_common_holidays() + + if self._year >= 1953: + # Victoria Day. + self._add_holiday_1st_mon_before_may_24(tr("Victoria Day")) + + if self._year >= 1879: + self._add_observed(self._canada_day) + + if self._year >= 2021: + self._add_observed( + # National Day for Truth and Reconciliation. + self._add_holiday_sep_30(tr("National Day for Truth and Reconciliation")) + ) + + self._add_thanksgiving_day() + + if self._year >= 1931: + # Remembrance Day. + self._add_observed(self._add_remembrance_day(tr("Remembrance Day"))) + + self._add_observed(self._christmas_day, rule=SAT_SUN_TO_NEXT_MON_TUE) # Boxing Day. - self._add_observed(self._add_christmas_day_two(tr("Boxing Day")), days=+2) + self._add_observed( + self._add_christmas_day_two(tr("Boxing Day")), rule=SAT_SUN_TO_NEXT_MON_TUE + ) + + def _populate_optional_holidays(self): + if self._year <= 1866: + return None + + # Christmas Day. + self._add_observed( + self._add_christmas_day(tr("Christmas Day")), rule=SAT_SUN_TO_NEXT_MON_TUE + ) - def _add_family_day(self): - # Family Day. - self._add_holiday_3rd_mon_of_feb(tr("Family Day")) + # Boxing Day. + self._add_observed( + self._add_christmas_day_two(tr("Boxing Day")), rule=SAT_SUN_TO_NEXT_MON_TUE + ) - def _add_thanksgiving(self): + def _add_thanksgiving_day(self): if self._year >= 1931: - # Thanksgiving. - name = tr("Thanksgiving") + # Thanksgiving Day. + name = tr("Thanksgiving Day") # in 1935, Canadian Thanksgiving was moved due to the General # Election falling on the second Monday of October # http://tiny.cc/can_thkgvg @@ -107,47 +162,41 @@ def _add_thanksgiving(self): else: self._add_holiday_2nd_mon_of_oct(name) - def _add_queens_funeral(self): - if self._year == 2022: - # Funeral of Queen Elizabeth II. - self._add_holiday_sep_19(tr("Funeral of Her Majesty the Queen Elizabeth II")) - - def _add_subdiv_holidays(self): - if self._year >= 1983: - self._add_observed( - self._add_holiday_jul_1( - ( - # Memorial Day. - tr("Memorial Day") - if self.subdiv == "NL" - # Canada Day. - else tr("Canada Day") - ) - ) - ) - - super()._add_subdiv_holidays() - - def _add_subdiv_ab_holidays(self): + def _add_subdiv_ab_public_holidays(self): if self._year >= 1990: - self._add_family_day() + # Family Day. + self._add_holiday_3rd_mon_of_feb(tr("Family Day")) if self._year >= 1953: # Victoria Day. self._add_holiday_1st_mon_before_may_24(tr("Victoria Day")) + if self._year >= 1879: + self._add_observed(self._canada_day, rule=SUN_TO_NEXT_MON) + + self._add_thanksgiving_day() + + if self._year >= 1931: + # Remembrance Day. + self._add_observed(self._add_remembrance_day(tr("Remembrance Day"))) + + def _add_subdiv_ab_optional_holidays(self): + # Easter Monday. + self._add_easter_monday(tr("Easter Monday")) + # https://en.wikipedia.org/wiki/Civic_Holiday#Alberta if self._year >= 1974: # Heritage Day. self._add_holiday_1st_mon_of_aug(tr("Heritage Day")) - self._add_thanksgiving() + if self._year >= 2021: + # National Day for Truth and Reconciliation. + self._add_holiday_sep_30(tr("National Day for Truth and Reconciliation")) - if self._year >= 1931: - # Remembrance Day. - self._add_remembrance_day(tr("Remembrance Day")) + # Boxing Day. + self._add_christmas_day_two(tr("Boxing Day")) - def _add_subdiv_bc_holidays(self): + def _add_subdiv_bc_public_holidays(self): if self._year >= 2013: name = tr("Family Day") if self._year >= 2019: @@ -159,24 +208,29 @@ def _add_subdiv_bc_holidays(self): # Victoria Day. self._add_holiday_1st_mon_before_may_24(tr("Victoria Day")) + if self._year >= 1879: + self._add_observed(self._canada_day, rule=SUN_TO_NEXT_MON) + # https://en.wikipedia.org/wiki/Civic_Holiday#British_Columbia if self._year >= 1974: # British Columbia Day. self._add_holiday_1st_mon_of_aug(tr("British Columbia Day")) - self._add_queens_funeral() + if self._year == 2022: + # Funeral of Queen Elizabeth II. + self._add_holiday_sep_19(tr("Funeral of Her Majesty the Queen Elizabeth II")) if self._year >= 2023: # National Day for Truth and Reconciliation. self._add_holiday_sep_30(tr("National Day for Truth and Reconciliation")) - self._add_thanksgiving() + self._add_thanksgiving_day() if self._year >= 1931: # Remembrance Day. self._add_remembrance_day(tr("Remembrance Day")) - def _add_subdiv_mb_holidays(self): + def _add_subdiv_mb_public_holidays(self): if self._year >= 2008: # Louis Riel Day. self._add_holiday_3rd_mon_of_feb(tr("Louis Riel Day")) @@ -185,6 +239,9 @@ def _add_subdiv_mb_holidays(self): # Victoria Day. self._add_holiday_1st_mon_before_may_24(tr("Victoria Day")) + self._add_thanksgiving_day() + + def _add_subdiv_mb_optional_holidays(self): if self._year >= 1900: name = ( # Terry Fox Day. @@ -195,36 +252,55 @@ def _add_subdiv_mb_holidays(self): ) self._add_holiday_1st_mon_of_aug(name) - if self._year >= 2021: - # National Day for Truth and Reconciliation. - self._add_holiday_sep_30(tr("National Day for Truth and Reconciliation")) - - self._add_thanksgiving() - if self._year >= 1931: # Remembrance Day. self._add_remembrance_day(tr("Remembrance Day")) - def _add_subdiv_nb_holidays(self): + def _add_subdiv_nb_public_holidays(self): if self._year >= 2018: - self._add_family_day() - - if self._year >= 1953: - # Victoria Day. - self._add_holiday_1st_mon_before_may_24(tr("Victoria Day")) + # Family Day. + self._add_holiday_3rd_mon_of_feb(tr("Family Day")) # https://en.wikipedia.org/wiki/Civic_Holiday#New_Brunswick - if self._year >= 1900: + if self._year >= 1975: # New Brunswick Day. self._add_holiday_1st_mon_of_aug(tr("New Brunswick Day")) - self._add_queens_funeral() + if self._year == 2022: + # Funeral of Queen Elizabeth II. + self._add_holiday_sep_19(tr("Funeral of Her Majesty the Queen Elizabeth II")) if self._year >= 1931: # Remembrance Day. self._add_remembrance_day(tr("Remembrance Day")) - def _add_subdiv_nl_holidays(self): + def _add_subdiv_nb_optional_holidays(self): + if self._year >= 1953: + # Victoria Day. + self._add_holiday_1st_mon_before_may_24(tr("Victoria Day")) + + self._add_thanksgiving_day() + + # Boxing Day. + self._add_christmas_day_two(tr("Boxing Day")) + + def _add_subdiv_nl_public_holidays(self): + if self._year >= 1917: + # Memorial Day. + self._add_holiday_jul_1(tr("Memorial Day")) + + if self._year >= 1879: + self._add_observed(self._canada_day) + + if self._year == 2022: + # Funeral of Queen Elizabeth II. + self._add_holiday_sep_19(tr("Funeral of Her Majesty the Queen Elizabeth II")) + + if self._year >= 1931: + # Remembrance Day. + self._add_observed(self._add_remembrance_day(tr("Remembrance Day"))) + + def _add_subdiv_nl_optional_holidays(self): if self._year >= 1900: # St. Patrick's Day. self._add_holiday(tr("St. Patrick's Day"), self._get_nearest_monday(MAR, 17)) @@ -241,29 +317,35 @@ def _add_subdiv_nl_holidays(self): # Discovery Day. self._add_holiday(tr("Discovery Day"), self._get_nearest_monday(JUN, 24)) - self._add_queens_funeral() + if self._year >= 1900: + # Orangemen's Day. + self._add_holiday(tr("Orangemen's Day"), self._get_nearest_monday(JUL, 12)) - if self._year >= 1931: - # Remembrance Day. - self._add_observed(self._add_remembrance_day(tr("Remembrance Day")), include_sat=False) + self._add_thanksgiving_day() + + # Boxing Day. + self._add_christmas_day_two(tr("Boxing Day")) - def _add_subdiv_ns_holidays(self): + def _add_subdiv_ns_public_holidays(self): # http://novascotia.ca/lae/employmentrights/NovaScotiaHeritageDay.asp if self._year >= 2015: # Heritage Day. self._add_holiday_3rd_mon_of_feb(tr("Heritage Day")) - self._add_queens_funeral() - - if self._year >= 2021: - # National Day for Truth and Reconciliation. - self._add_holiday_sep_30(tr("National Day for Truth and Reconciliation")) + if self._year == 2022: + # Funeral of Queen Elizabeth II. + self._add_holiday_sep_19(tr("Funeral of Her Majesty the Queen Elizabeth II")) - if self._year >= 1931: + if self._year >= 1981: # Remembrance Day. - self._add_observed(self._add_remembrance_day(tr("Remembrance Day")), include_sat=False) + self._add_observed(self._add_remembrance_day(tr("Remembrance Day"))) + + def _add_subdiv_ns_optional_holidays(self): + if self._year >= 1996: + # Natal Day. + self._add_holiday_1st_mon_of_aug(tr("Natal Day")) - def _add_subdiv_nt_holidays(self): + def _add_subdiv_nt_public_holidays(self): if self._year >= 1953: # Victoria Day. self._add_holiday_1st_mon_before_may_24(tr("Victoria Day")) @@ -276,43 +358,63 @@ def _add_subdiv_nt_holidays(self): # Civic Holiday. self._add_holiday_1st_mon_of_aug(tr("Civic Holiday")) - self._add_thanksgiving() + if self._year >= 2022: + # National Day for Truth and Reconciliation. + self._add_holiday_sep_30(tr("National Day for Truth and Reconciliation")) + + self._add_thanksgiving_day() if self._year >= 1931: # Remembrance Day. - self._add_observed(self._add_remembrance_day(tr("Remembrance Day")), include_sat=False) + self._add_remembrance_day(tr("Remembrance Day")) - def _add_subdiv_nu_holidays(self): + def _add_subdiv_nu_public_holidays(self): if self._year >= 1953: # Victoria Day. self._add_holiday_1st_mon_before_may_24(tr("Victoria Day")) - if self._year >= 2000: - dt = (APR, 1) if self._year == 2000 else (JUL, 9) - # Nunavut Day. - self._add_observed(self._add_holiday(tr("Nunavut Day"), dt), include_sat=False) + if self._year >= 1900: + # Civic Holiday. + self._add_holiday_1st_mon_of_aug(tr("Civic Holiday")) - self._add_thanksgiving() + if self._year >= 2022: + # National Day for Truth and Reconciliation. + self._add_holiday_sep_30(tr("National Day for Truth and Reconciliation")) + + self._add_thanksgiving_day() if self._year >= 1931: # Remembrance Day. self._add_remembrance_day(tr("Remembrance Day")) - def _add_subdiv_on_holidays(self): + def _add_subdiv_nu_optional_holidays(self): + if self._year >= 2000: + # Nunavut Day. + name = tr("Nunavut Day") + if self._year == 2000: + self._add_holiday_apr_1(name) + else: + self._add_holiday_jul_9(name) + + def _add_subdiv_on_public_holidays(self): if self._year >= 2008: - self._add_family_day() + # Family Day. + self._add_holiday_3rd_mon_of_feb(tr("Family Day")) if self._year >= 1953: # Victoria Day. self._add_holiday_1st_mon_before_may_24(tr("Victoria Day")) + self._add_thanksgiving_day() + + self._add_observed(self._add_christmas_day_two(tr("Boxing Day")), rule=SUN_TO_NEXT_TUE) + + def _add_subdiv_on_optional_holidays(self): if self._year >= 1900: # Civic Holiday. self._add_holiday_1st_mon_of_aug(tr("Civic Holiday")) - self._add_thanksgiving() - - def _add_subdiv_pe_holidays(self): + def _add_subdiv_pe_public_holidays(self): if self._year >= 2009: # Islander Day. name = tr("Islander Day") @@ -321,13 +423,22 @@ def _add_subdiv_pe_holidays(self): else: self._add_holiday_2nd_mon_of_feb(name) - self._add_queens_funeral() + if self._year >= 1879: + self._add_observed(self._canada_day) + + if self._year == 2022: + # Funeral of Queen Elizabeth II. + self._add_holiday_sep_19(tr("Funeral of Her Majesty the Queen Elizabeth II")) + + if self._year >= 2022: + # National Day for Truth and Reconciliation. + self._add_holiday_sep_30(tr("National Day for Truth and Reconciliation")) if self._year >= 1931: # Remembrance Day. - self._add_observed(self._add_remembrance_day(tr("Remembrance Day")), include_sat=False) + self._add_observed(self._add_remembrance_day(tr("Remembrance Day"))) - def _add_subdiv_qc_holidays(self): + def _add_subdiv_qc_public_holidays(self): if self._year >= 2003: # National Patriots' Day. self._add_holiday_1st_mon_before_may_24(tr("National Patriots' Day")) @@ -336,57 +447,75 @@ def _add_subdiv_qc_holidays(self): self._add_observed( # St. Jean Baptiste Day. self._add_saint_johns_day(tr("St. Jean Baptiste Day")), - include_sat=False, + rule=SUN_TO_NEXT_MON, ) - self._add_thanksgiving() + if self._year >= 1879: + self._add_observed(self._canada_day, rule=SUN_TO_NEXT_MON) + + self._add_thanksgiving_day() + + def _add_subdiv_qc_optional_holidays(self): + # Easter Monday. + self._add_easter_monday(tr("Easter Monday")) - def _add_subdiv_sk_holidays(self): + def _add_subdiv_sk_public_holidays(self): if self._year >= 2007: - self._add_family_day() + # Family Day. + self._add_holiday_3rd_mon_of_feb(tr("Family Day")) if self._year >= 1953: # Victoria Day. self._add_holiday_1st_mon_before_may_24(tr("Victoria Day")) + if self._year >= 1879: + self._add_observed(self._canada_day) + # https://en.wikipedia.org/wiki/Civic_Holiday#Saskatchewan if self._year >= 1900: # Saskatchewan Day. self._add_holiday_1st_mon_of_aug(tr("Saskatchewan Day")) - self._add_thanksgiving() + self._add_thanksgiving_day() if self._year >= 1931: # Remembrance Day. - self._add_observed(self._add_remembrance_day(tr("Remembrance Day")), include_sat=False) - - def _add_subdiv_yt_holidays(self): - # start date? - # https://www.britannica.com/topic/Heritage-Day-Canadian-holiday - # Heritage Day was created in 1973 - # by the Heritage Canada Foundation - # therefore, start date is not earlier than 1974 - # http://heritageyukon.ca/programs/heritage-day - # https://en.wikipedia.org/wiki/Family_Day_(Canada)#Yukon_Heritage_Day - # Friday before the last Sunday in February - if self._year >= 1974: - self._add_holiday_2_days_prior_last_sun_of_feb(tr("Heritage Day")) + self._add_observed(self._add_remembrance_day(tr("Remembrance Day"))) + def _add_subdiv_yt_public_holidays(self): if self._year >= 1953: # Victoria Day. self._add_holiday_1st_mon_before_may_24(tr("Victoria Day")) + if self._year >= 2017: + # National Aboriginal Day. + self._add_holiday_jun_21(tr("National Aboriginal Day")) + + if self._year >= 1879: + self._add_observed(self._canada_day) + if self._year >= 1912: # Discovery Day. self._add_holiday_3rd_mon_of_aug(tr("Discovery Day")) - self._add_queens_funeral() + if self._year == 2022: + # Funeral of Queen Elizabeth II. + self._add_holiday_sep_19(tr("Funeral of Her Majesty the Queen Elizabeth II")) + + if self._year >= 2023: + # National Day for Truth and Reconciliation. + self._add_holiday_sep_30(tr("National Day for Truth and Reconciliation")) - self._add_thanksgiving() + self._add_thanksgiving_day() if self._year >= 1931: # Remembrance Day. - self._add_remembrance_day(tr("Remembrance Day")) + self._add_observed(self._add_remembrance_day(tr("Remembrance Day"))) + + def _add_subdiv_yt_optional_holidays(self): + # Friday before the last Sunday in February + if self._year >= 1976: + self._add_holiday_2_days_prior_last_sun_of_feb(tr("Heritage Day")) class CA(Canada): diff --git a/holidays/countries/chad.py b/holidays/countries/chad.py index 6596b3538..c9abab176 100644 --- a/holidays/countries/chad.py +++ b/holidays/countries/chad.py @@ -9,16 +9,13 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.calendars import _CustomIslamicCalendar from holidays.calendars.gregorian import JAN, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC from holidays.groups import ChristianHolidays, InternationalHolidays, IslamicHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class Chad(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): +class Chad(ObservedHolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Chad @@ -26,19 +23,16 @@ class Chad(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHoliday """ country = "TD" + observed_label = "%s (Observed)" special_holidays = { 2021: (APR, 23, "Funeral of Idriss Déby Itno"), } - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self, calendar=ChadIslamicCalendar()) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date) -> None: - if self.observed and self._is_sunday(dt): - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=+1)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): # On 11 August 1960, Chad gained independence from France. diff --git a/holidays/countries/chile.py b/holidays/countries/chile.py index 7e5210e1e..abb7733bb 100644 --- a/holidays/countries/chile.py +++ b/holidays/countries/chile.py @@ -9,17 +9,21 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date from datetime import timedelta as td from gettext import gettext as tr from typing import Tuple -from holidays.calendars.gregorian import JUN, SEP, OCT, MON, _get_nth_weekday_from +from holidays.calendars.gregorian import JUN, SEP from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + TUE_TO_PREV_FRI, + WED_TO_NEXT_FRI, + WORKDAY_TO_NEAREST_MON, +) -class Chile(HolidayBase, ChristianHolidays, InternationalHolidays): +class Chile(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ References: - https://www.feriados.cl @@ -74,15 +78,9 @@ class Chile(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _move_holiday(self, dt: date) -> None: - if self._year <= 1999 or self._is_monday(dt) or self._is_weekend(dt): - return None - self._add_holiday( - self[dt], _get_nth_weekday_from(+1 if self._is_friday(dt) else -1, MON, dt) + super().__init__( + observed_rule=WORKDAY_TO_NEAREST_MON, observed_since=2000, *args, **kwargs ) - self.pop(dt) def _populate(self, year): if year <= 1914: @@ -177,15 +175,15 @@ def _populate(self, year): self._move_holiday(self._add_columbus_day(name)) if year >= 2008: - dt = date(year, OCT, 31) # This holiday is moved to the preceding Friday if it falls on a Tuesday, # or to the following Friday if it falls on a Wednesday. - if self._is_wednesday(dt): - dt += td(days=+2) - elif self._is_tuesday(dt): - dt += td(days=-4) - # National Day of the Evangelical and Protestant Churches. - self._add_holiday(tr("Día Nacional de las Iglesias Evangélicas y Protestantes"), dt) + self._move_holiday( + self._add_holiday_oct_31( + # National Day of the Evangelical and Protestant Churches. + tr("Día Nacional de las Iglesias Evangélicas y Protestantes") + ), + rule=TUE_TO_PREV_FRI + WED_TO_NEXT_FRI, + ) # All Saints Day. self._add_all_saints_day(tr("Día de Todos los Santos")) diff --git a/holidays/countries/colombia.py b/holidays/countries/colombia.py index 25ca46f31..c354a3d27 100644 --- a/holidays/countries/colombia.py +++ b/holidays/countries/colombia.py @@ -9,54 +9,45 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date from datetime import timedelta as td from gettext import gettext as tr -from holidays.calendars.gregorian import MON, _get_nth_weekday_from from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, ALL_TO_NEXT_MON -class Colombia(HolidayBase, ChristianHolidays, InternationalHolidays): +class Colombia(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ Colombia has 18 holidays. The establishing of these are by: Ley 35 de 1939 (DEC 4): https://bit.ly/3PJwk7B Decreto 2663 de 1950 (AUG 5): https://bit.ly/3PJcut8 Decreto 3743 de 1950 (DEC 20): https://bit.ly/3B9Otr3 Ley 51 de 1983 (DEC 6): https://bit.ly/3aSobiB + + On the 6th of December 1983, the government of Colombia declared which + holidays are to take effect, and also clarified that a subset of them + are to take place the next Monday if they do not fall on a Monday. + This law is "Ley 51 de 1983" which translates to law 51 of 1983. + Link: https://bit.ly/3PtPi2e + A few links below to calendars from the 1980s to demonstrate this law + change. In 1984 some calendars still use the old rules, presumably + because they were printed prior to the declaration of law change. + 1981: https://bit.ly/3BbgKOc + 1982: https://bit.ly/3BdbhWW + 1984: https://bit.ly/3PqGxWU + 1984: https://bit.ly/3B7ogt8 """ country = "CO" default_language = "es" + # %s (Observed). + observed_label = tr("%s (Observado)") supported_languages = ("en_US", "es", "uk") def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _move_holiday(self, dt: date) -> None: - """ - On the 6th of December 1983, the government of Colombia declared which - holidays are to take effect, and also clarified that a subset of them - are to take place the next Monday if they do not fall on a Monday. - This law is "Ley 51 de 1983" which translates to law 51 of 1983. - Link: https://bit.ly/3PtPi2e - A few links below to calendars from the 1980s to demonstrate this law - change. In 1984 some calendars still use the old rules, presumably - because they were printed prior to the declaration of law change. - 1981: https://bit.ly/3BbgKOc - 1982: https://bit.ly/3BdbhWW - 1984: https://bit.ly/3PqGxWU - 1984: https://bit.ly/3B7ogt8 - """ - - if self.observed and not self._is_monday(dt) and self._year >= 1984: - self._add_holiday( - self.tr("%s (Observado)") % self[dt], _get_nth_weekday_from(+1, MON, dt) - ) - self.pop(dt) + super().__init__(observed_rule=ALL_TO_NEXT_MON, observed_since=1984, *args, **kwargs) def _populate(self, year): super()._populate(year) diff --git a/holidays/countries/costa_rica.py b/holidays/countries/costa_rica.py index 403b10866..361085159 100644 --- a/holidays/countries/costa_rica.py +++ b/holidays/countries/costa_rica.py @@ -9,15 +9,18 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date from gettext import gettext as tr -from holidays.calendars.gregorian import MON, _get_nth_weekday_from from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + ALL_TO_NEAREST_MON_LATAM, + ALL_TO_NEXT_SUN, + WORKDAY_TO_NEXT_MON, +) -class CostaRica(HolidayBase, ChristianHolidays, InternationalHolidays): +class CostaRica(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Costa_Rica @@ -31,22 +34,14 @@ class CostaRica(HolidayBase, ChristianHolidays, InternationalHolidays): country = "CR" default_language = "es" + # %s (Observed). + observed_label = tr("%s (Observado)") supported_languages = ("en_US", "es", "uk") def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _move_holiday(self, dt: date, forward: bool = False) -> None: - if not self.observed or self._is_monday(dt) or (forward and self._is_weekend(dt)): - return None - - dt_observed = _get_nth_weekday_from( - +1 if forward or not (self._is_tuesday(dt) or self._is_wednesday(dt)) else -1, MON, dt - ) - self._add_holiday(self.tr("%s (Observado)") % self[dt], dt_observed) - self.pop(dt) + super().__init__(observed_rule=ALL_TO_NEAREST_MON_LATAM, *args, **kwargs) def _populate(self, year): super()._populate(year) @@ -61,11 +56,11 @@ def _populate(self, year): self._add_good_friday(tr("Viernes Santo")) # Juan Santamaría Day. - dt = self._add_holiday_apr_11(tr("Día de Juan Santamaría")) + apr_11 = self._add_holiday_apr_11(tr("Día de Juan Santamaría")) if 2006 <= year <= 2010: - self._move_holiday(dt, forward=True) + self._move_holiday(apr_11, rule=WORKDAY_TO_NEXT_MON) elif year in {2023, 2024}: - self._move_holiday(dt) + self._move_holiday(apr_11) # International Labor Day. dt = self._add_labor_day(tr("Día Internacional del Trabajo")) @@ -73,11 +68,11 @@ def _populate(self, year): self._move_holiday(dt) # Annexation of the Party of Nicoya to Costa Rica. - dt = self._add_holiday_jul_25(tr("Anexión del Partido de Nicoya a Costa Rica")) + jul_25 = self._add_holiday_jul_25(tr("Anexión del Partido de Nicoya a Costa Rica")) if 2005 <= year <= 2008: - self._move_holiday(dt, forward=True) + self._move_holiday(jul_25, rule=WORKDAY_TO_NEXT_MON) elif 2020 <= year <= 2024: - self._move_holiday(dt) + self._move_holiday(jul_25) # Feast of Our Lady of the Angels. self._add_holiday_aug_2(tr("Fiesta de Nuestra Señora de los Ángeles")) @@ -85,17 +80,18 @@ def _populate(self, year): # Mother's Day. dt = self._add_assumption_of_mary_day(tr("Día de la Madre")) if 2005 <= year <= 2007: - self._move_holiday(dt, forward=True) + self._move_holiday(dt, rule=WORKDAY_TO_NEXT_MON) elif year in {2020, 2023, 2024}: self._move_holiday(dt) if year >= 2022: - # Day of the Black Person and Afro-Costa Rican Culture. - name = self.tr("Día de la Persona Negra y la Cultura Afrocostarricense") - if self.observed and year in {2022, 2023}: - self._add_holiday_1st_sun_from_aug_31(self.tr("%s (Observado)") % name) - else: - self._add_holiday_aug_31(name) + aug_31 = self._add_holiday_aug_31( + # Day of the Black Person and Afro-Costa Rican Culture. + self.tr("Día de la Persona Negra y la Cultura Afrocostarricense") + ) + if year in {2022, 2023}: + # Move to next Sunday. + self._move_holiday(aug_31, rule=ALL_TO_NEXT_SUN) # Independence Day. sep_15 = self._add_holiday_sep_15(tr("Día de la Independencia")) @@ -103,8 +99,11 @@ def _populate(self, year): self._move_holiday(sep_15) if year <= 2019: - # Cultures Day. - self._move_holiday(self._add_columbus_day(tr("Día de las Culturas")), forward=True) + self._move_holiday( + # Cultures Day. + self._add_columbus_day(tr("Día de las Culturas")), + rule=WORKDAY_TO_NEXT_MON, + ) if year >= 2020: # Army Abolition Day. diff --git a/holidays/countries/cuba.py b/holidays/countries/cuba.py index 596aca85d..caff44848 100644 --- a/holidays/countries/cuba.py +++ b/holidays/countries/cuba.py @@ -9,15 +9,13 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td from gettext import gettext as tr from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class Cuba(HolidayBase, ChristianHolidays, InternationalHolidays): +class Cuba(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ Overview: https://en.wikipedia.org/wiki/Public_holidays_in_Cuba 1984 (DEC 28): https://bit.ly/3okNBbt @@ -34,28 +32,26 @@ class Cuba(HolidayBase, ChristianHolidays, InternationalHolidays): country = "CU" default_language = "es" + # %s Observed. + observed_label = tr("%s (Observado)") supported_languages = ("en_US", "es", "uk") def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): # This calendar only works from 1959 onwards. if year <= 1958: return None - def _add_observed(dt: date) -> None: - if self.observed and self._is_sunday(dt): - self._add_holiday(self.tr("%s (Observado)") % self[dt], dt + td(days=+1)) - super()._populate(year) # Liberation Day. jan_1 = self._add_holiday_jan_1(tr("Triunfo de la Revolución")) if year <= 2013: - _add_observed(jan_1) + self._add_observed(jan_1) # Granted in 2007 decree. if year >= 2008: @@ -71,7 +67,7 @@ def _add_observed(dt: date) -> None: self._add_good_friday(tr("Viernes Santo")) # Labour Day. - _add_observed(self._add_labor_day(tr("Día Internacional de los Trabajadores"))) + self._add_observed(self._add_labor_day(tr("Día Internacional de los Trabajadores"))) # Commemoration of the Assault of the Moncada garrison. self._add_holiday_jul_25(tr("Conmemoración del asalto a Moncada")) @@ -83,7 +79,7 @@ def _add_observed(dt: date) -> None: self._add_holiday_jul_27(tr("Conmemoración del asalto a Moncada")) # Independence Day. - _add_observed(self._add_holiday_oct_10(tr("Inicio de las Guerras de Independencia"))) + self._add_observed(self._add_holiday_oct_10(tr("Inicio de las Guerras de Independencia"))) # In 1969, Christmas was cancelled for the sugar harvest but then was # cancelled for good: diff --git a/holidays/countries/dominican_republic.py b/holidays/countries/dominican_republic.py index e865a7fa6..58a8d4e95 100644 --- a/holidays/countries/dominican_republic.py +++ b/holidays/countries/dominican_republic.py @@ -12,12 +12,17 @@ from datetime import date from gettext import gettext as tr -from holidays.calendars.gregorian import JUN, MON, _get_nth_weekday_from +from holidays.calendars.gregorian import JUN from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + TUE_WED_TO_PREV_MON, + THU_FRI_TO_NEXT_MON, + THU_FRI_SUN_TO_NEXT_MON, +) -class DominicanRepublic(HolidayBase, ChristianHolidays, InternationalHolidays): +class DominicanRepublic(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ http://ojd.org.do/Normativas/LABORAL/Leyes/Ley%20No.%20%20139-97.pdf https://es.wikipedia.org/wiki/Rep%C3%BAblica_Dominicana#D%C3%ADas_festivos_nacionales @@ -27,25 +32,14 @@ class DominicanRepublic(HolidayBase, ChristianHolidays, InternationalHolidays): default_language = "es" supported_languages = ("en_US", "es", "uk") - def _move_holiday(self, dt: date, include_sun: bool = False) -> None: - # Law No. 139-97 - Holidays Dominican Republic - Jun 27, 1997 - if dt < date(1997, JUN, 27): - return None - - dt_observed = None - if self._is_tuesday(dt) or self._is_wednesday(dt): - dt_observed = _get_nth_weekday_from(-1, MON, dt) - elif self._is_thursday(dt) or self._is_friday(dt) or (include_sun and self._is_sunday(dt)): - dt_observed = _get_nth_weekday_from(+1, MON, dt) - - if dt_observed: - self._add_holiday(self[dt], dt_observed) - self.pop(dt) - - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=TUE_WED_TO_PREV_MON + THU_FRI_TO_NEXT_MON, *args, **kwargs) + + def _is_observed(self, dt: date) -> bool: + # Law No. 139-97 - Holidays Dominican Republic - Jun 27, 1997 + return dt >= date(1997, JUN, 27) def _populate(self, year): super()._populate(year) @@ -68,8 +62,11 @@ def _populate(self, year): # Good Friday. self._add_good_friday(tr("Viernes Santo")) - # Labor Day. - self._move_holiday(self._add_labor_day(tr("Día del Trabajo")), include_sun=True) + self._move_holiday( + # Labor Day. + self._add_labor_day(tr("Día del Trabajo")), + rule=TUE_WED_TO_PREV_MON + THU_FRI_SUN_TO_NEXT_MON, + ) # Feast of Corpus Christi. self._add_corpus_christi_day(tr("Corpus Christi")) diff --git a/holidays/countries/ecuador.py b/holidays/countries/ecuador.py index 8005da5c1..5c200d1d6 100644 --- a/holidays/countries/ecuador.py +++ b/holidays/countries/ecuador.py @@ -9,16 +9,21 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td from gettext import gettext as tr from holidays.calendars.gregorian import DEC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + TUE_TO_PREV_MON, + WED_TO_NEXT_FRI, + SAT_TO_PREV_FRI, + SUN_TO_NEXT_MON, + WED_THU_TO_NEXT_FRI, +) -class Ecuador(HolidayBase, ChristianHolidays, InternationalHolidays): +class Ecuador(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Ecuador @@ -27,51 +32,40 @@ class Ecuador(HolidayBase, ChristianHolidays, InternationalHolidays): country = "EC" default_language = "es" + # %s (Observed). + observed_label = tr("%s (Observado)") supported_languages = ("en_US", "es", "uk") def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed( - self, dt: date, weekend_only: bool = False, before: bool = True, after: bool = True - ) -> None: - if self.observed and self._year >= 2017: - dt_observed = None - # Art. 1 of Law #0 from 20.12.2016 - # When holidays falls on Tuesday, the rest shall be transferred to - # preceding Monday, and if they falls on Wednesday or Thursday, - # the rest shall be transferred to Friday of the same week. - # Exceptions to this provision are January 1, December 25 and - # Shrove Tuesday. - if not weekend_only: - if self._is_tuesday(dt) and before: - dt_observed = dt + td(days=-1) - elif self._is_wednesday(dt): - dt_observed = dt + td(days=+2) - elif self._is_thursday(dt) and after: - dt_observed = dt + td(days=+1) - # When holidays falls on Saturday or Sunday, the rest shall be - # transferred, respectively, to the preceding Friday or the - # following Monday. - if self._is_saturday(dt) and before: - dt_observed = dt + td(days=-1) - elif self._is_sunday(dt) and after: - dt_observed = dt + td(days=+1) - if dt_observed: - self._add_holiday(self.tr("%s (Observado)") % self[dt], dt_observed) + # Art. 1 of Law #0 from 20.12.2016 + # When holidays falls on Tuesday, the rest shall be transferred to + # preceding Monday, and if they falls on Wednesday or Thursday, + # the rest shall be transferred to Friday of the same week. + # Exceptions to this provision are January 1, December 25 and + # Shrove Tuesday. + # When holidays falls on Saturday or Sunday, the rest shall be + # transferred, respectively, to the preceding Friday or the + # following Monday. + super().__init__( + observed_rule=( + TUE_TO_PREV_MON + WED_THU_TO_NEXT_FRI + SAT_TO_PREV_FRI + SUN_TO_NEXT_MON + ), + observed_since=2017, + *args, + **kwargs, + ) def _populate(self, year): super()._populate(year) # New Year's Day. name = self.tr("Año Nuevo") - self._add_observed(self._add_new_years_day(name), weekend_only=True) + self._add_observed(self._add_new_years_day(name), rule=SAT_TO_PREV_FRI + SUN_TO_NEXT_MON) - if self.observed and year >= 2017: - if self._is_friday(DEC, 31): - self._add_holiday_dec_31(self.tr("%s (Observado)") % name) + if self.observed and self._is_friday(DEC, 31) and year >= 2017: + self._add_holiday_dec_31(self.tr(self.observed_label) % name) # Carnival. name = tr("Carnaval") @@ -93,14 +87,23 @@ def _populate(self, year): # Independence of Guayaquil. self._add_observed(self._add_holiday_oct_9(tr("Independencia de Guayaquil"))) - # All Souls' Day. - self._add_observed(self._add_all_souls_day(tr("Día de los Difuntos")), after=False) - - # Independence of Cuenca. - self._add_observed(self._add_holiday_nov_3(tr("Independencia de Cuenca")), before=False) - - # Christmas Day. - self._add_observed(self._add_christmas_day(tr("Día de Navidad")), weekend_only=True) + self._add_observed( + # All Souls' Day. + self._add_all_souls_day(tr("Día de los Difuntos")), + rule=TUE_TO_PREV_MON + WED_TO_NEXT_FRI + SAT_TO_PREV_FRI, # Not observed the next day. + ) + + self._add_observed( + # Independence of Cuenca. + self._add_holiday_nov_3(tr("Independencia de Cuenca")), + rule=WED_THU_TO_NEXT_FRI + SUN_TO_NEXT_MON, # Not observed the previous day. + ) + + self._add_observed( + # Christmas Day. + self._add_christmas_day(tr("Día de Navidad")), + rule=SAT_TO_PREV_FRI + SUN_TO_NEXT_MON, + ) class EC(Ecuador): diff --git a/holidays/countries/eswatini.py b/holidays/countries/eswatini.py index 77e761a4e..72c9e4c29 100644 --- a/holidays/countries/eswatini.py +++ b/holidays/countries/eswatini.py @@ -10,21 +10,20 @@ # License: MIT (see LICENSE file) import warnings -from datetime import date -from datetime import timedelta as td from holidays.calendars.gregorian import JAN, DEC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON, SUN_TO_NEXT_TUE -class Eswatini(HolidayBase, ChristianHolidays, InternationalHolidays): +class Eswatini(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://swazilii.org/sz/legislation/act/1938/71 https://www.officeholidays.com/countries/swaziland """ country = "SZ" + observed_label = "%s (Observed)" special_holidays = { # https://mg.co.za/article/1999-12-09-swaziland-declares-bank-holidays/ 1999: (DEC, 31, "Y2K changeover"), @@ -34,13 +33,7 @@ class Eswatini(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, days: int = +1) -> None: - # As of 2021/1/1, whenever a public holiday falls on a Sunday - # it rolls over to the following Monday - if self.observed and self._is_sunday(dt) and self._year >= 2021: - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=days)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, observed_since=2021, *args, **kwargs) def _populate(self, year): # Observed since 1939 @@ -58,12 +51,16 @@ def _populate(self, year): self._add_ascension_thursday("Ascension Day") if year >= 1987: - apr_19 = self._add_holiday_apr_19("King's Birthday") - self._add_observed(apr_19, days=+2 if apr_19 == self._easter_sunday else +1) + self._add_observed( + apr_19 := self._add_holiday_apr_19("King's Birthday"), + rule=SUN_TO_NEXT_TUE if apr_19 == self._easter_sunday else SUN_TO_NEXT_MON, + ) if year >= 1969: - apr_25 = self._add_holiday_apr_25("National Flag Day") - self._add_observed(apr_25, days=+2 if apr_25 == self._easter_sunday else +1) + self._add_observed( + apr_25 := self._add_holiday_apr_25("National Flag Day"), + rule=SUN_TO_NEXT_TUE if apr_25 == self._easter_sunday else SUN_TO_NEXT_MON, + ) self._add_observed(self._add_labor_day("Worker's Day")) @@ -72,7 +69,7 @@ def _populate(self, year): self._add_observed(self._add_holiday_sep_6("Independence Day")) - self._add_observed(self._add_christmas_day("Christmas Day"), days=+2) + self._add_observed(self._add_christmas_day("Christmas Day"), rule=SUN_TO_NEXT_TUE) self._add_observed(self._add_christmas_day_two("Boxing Day")) diff --git a/holidays/countries/greece.py b/holidays/countries/greece.py index 282be0e0c..875a47ff3 100644 --- a/holidays/countries/greece.py +++ b/holidays/countries/greece.py @@ -9,17 +9,15 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import timedelta as td from gettext import gettext as tr -from holidays.calendars.gregorian import MON, _get_nth_weekday_from from holidays.calendars.julian_revised import JULIAN_REVISED_CALENDAR from holidays.constants import HALF_DAY, PUBLIC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SAT_SUN_TO_NEXT_WORKDAY -class Greece(HolidayBase, ChristianHolidays, InternationalHolidays): +class Greece(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ Greece holidays. @@ -29,13 +27,15 @@ class Greece(HolidayBase, ChristianHolidays, InternationalHolidays): country = "GR" default_language = "el" + # %s (Observed). + observed_label = tr("%s (παρατηρήθηκε)") supported_categories = {HALF_DAY, PUBLIC} supported_languages = ("el", "en_US", "uk") def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self, JULIAN_REVISED_CALENDAR) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_WORKDAY, *args, **kwargs) def _populate_public_holidays(self): # New Year's Day. @@ -60,19 +60,7 @@ def _populate_public_holidays(self): self._add_whit_monday(tr("Δευτέρα του Αγίου Πνεύματος")) # Labour Day. - name = self.tr("Εργατική Πρωτομαγιά") - may_1 = self._add_labor_day(name) - - if self.observed and self._is_weekend(may_1): - dt_observed = _get_nth_weekday_from(+1, MON, may_1) - # %s (Observed). - name_observed = self.tr("%s (παρατηρήθηκε)") % name - # In 2016 and 2021, Labour Day coincided with other holidays - # https://www.timeanddate.com/holidays/greece/labor-day - self._add_holiday( - name_observed, - dt_observed + td(days=+1) if dt_observed in self else dt_observed, - ) + self._add_observed(self._add_labor_day(self.tr("Εργατική Πρωτομαγιά"))) # Dormition of the Mother of God. self._add_assumption_of_mary_day(tr("Κοίμηση της Θεοτόκου")) diff --git a/holidays/countries/guatemala.py b/holidays/countries/guatemala.py index d5bdda7b9..3a600bd38 100644 --- a/holidays/countries/guatemala.py +++ b/holidays/countries/guatemala.py @@ -12,16 +12,23 @@ from datetime import date from gettext import gettext as tr -from holidays.calendars.gregorian import OCT, MON, _get_nth_weekday_from +from holidays.calendars.gregorian import OCT from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, ALL_TO_NEAREST_MON_LATAM -class Guatemala(HolidayBase, ChristianHolidays, InternationalHolidays): +class Guatemala(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ References: - http://www.bvnsa.com.gt/bvnsa/calendario_dias_festivos.php - https://www.minfin.gob.gt/images/downloads/leyes_acuerdos/decretocong19_101018.pdf + + Moving holidays: + law 19-2018 start 18 oct 2018 + https://www.minfin.gob.gt/images/downloads/leyes_acuerdos/decretocong19_101018.pdf + + EXPEDIENTE 5536-2018 (CC) start 17 abr 2020 + https://leyes.infile.com/index.php?id=181&id_publicacion=81051 """ country = "GT" @@ -31,26 +38,10 @@ class Guatemala(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=ALL_TO_NEAREST_MON_LATAM, *args, **kwargs) - def _move_holiday(self, dt: date) -> None: - """ - law 19-2018 start 18 oct 2018 - https://www.minfin.gob.gt/images/downloads/leyes_acuerdos/decretocong19_101018.pdf - - - EXPEDIENTE 5536-2018 (CC) start 17 abr 2020 - https://leyes.infile.com/index.php?id=181&id_publicacion=81051 - """ - if dt <= date(2018, OCT, 17) or self._is_monday(dt): - return None - self._add_holiday( - self[dt], - _get_nth_weekday_from(-1, MON, dt) - if self._is_tuesday(dt) or self._is_wednesday(dt) - else _get_nth_weekday_from(1, MON, dt), - ) - self.pop(dt) + def _is_observed(self, dt: date) -> bool: + return dt >= date(2018, OCT, 18) def _populate(self, year): super()._populate(year) diff --git a/holidays/countries/hongkong.py b/holidays/countries/hongkong.py index d2a055732..e11298ad5 100644 --- a/holidays/countries/hongkong.py +++ b/holidays/countries/hongkong.py @@ -13,12 +13,20 @@ from datetime import timedelta as td from typing import Optional -from holidays.calendars.gregorian import JUL, AUG, SEP, MON, _get_nth_weekday_of_month +from holidays.calendars.gregorian import JUL, AUG, SEP, MON, SUN, _get_nth_weekday_of_month from holidays.groups import ChineseCalendarHolidays, ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase - - -class HongKong(HolidayBase, ChineseCalendarHolidays, ChristianHolidays, InternationalHolidays): +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + WORKDAY_TO_NEXT_WORKDAY, + MON_TO_NEXT_TUE, + SUN_TO_NEXT_WORKDAY, + SAT_SUN_TO_NEXT_WORKDAY, +) + + +class HongKong( + ObservedHolidayBase, ChineseCalendarHolidays, ChristianHolidays, InternationalHolidays +): """ https://en.wikipedia.org/wiki/Public_holidays_in_Hong_Kong Holidays for 2007–2023 (government source): @@ -26,6 +34,7 @@ class HongKong(HolidayBase, ChineseCalendarHolidays, ChristianHolidays, Internat """ country = "HK" + observed_label = "The day following %s" special_holidays = { 1997: (JUL, 2, "Hong Kong Special Administrative Region Establishment Day"), 2015: ( @@ -42,15 +51,18 @@ def __init__(self, *args, **kwargs): ChineseCalendarHolidays.__init__(self) ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_holiday(self, name: str, dt: date) -> Optional[date]: - if self.observed and (self._is_sunday(dt) or dt in self): - while self._is_sunday(dt) or dt in self: - dt += td(days=+1) - name = self.tr("The day following %s") % self.tr(name) - - return super()._add_holiday(name, dt) + super().__init__(observed_rule=SUN_TO_NEXT_WORKDAY, *args, **kwargs) + + def _add_holiday(self, name: str, *args) -> Optional[date]: + dt = args if len(args) > 1 else args[0] + dt = dt if isinstance(dt, date) else date(self._year, *dt) + rule = ( + WORKDAY_TO_NEXT_WORKDAY + SAT_SUN_TO_NEXT_WORKDAY + if dt in self + else self._observed_rule + ) + is_obs, dt_observed = self._add_observed(dt, name=name, rule=rule) + return dt_observed if is_obs else super()._add_holiday(name, dt) # type: ignore[arg-type] def _populate(self, year): # Current set of holidays actually valid since 1946 @@ -58,8 +70,7 @@ def _populate(self, year): return None super()._populate(year) - - day_following = "The day following" + self.weekend = {SUN} # The first day of January self._add_new_years_day("The first day of January") @@ -96,7 +107,7 @@ def _populate(self, year): name = "Ching Ming Festival" dt_qingming = self._qingming_date if self.observed and dt_qingming == self._easter_sunday + td(days=+1): - self._add_holiday(f"{day_following} {name}", dt_qingming + td(days=+1)) + self._add_observed(dt_qingming, name=name, rule=MON_TO_NEXT_TUE) elif dt_qingming not in { self._easter_sunday + td(days=-2), self._easter_sunday + td(days=-1), @@ -107,7 +118,7 @@ def _populate(self, year): good_friday = "Good Friday" easter_monday = "Easter Monday" self._add_good_friday(good_friday) - self._add_holy_saturday(f"{day_following} {good_friday}") + self._add_holy_saturday(self.observed_label % good_friday) self._add_easter_monday(easter_monday) if dt_qingming in { diff --git a/holidays/countries/hungary.py b/holidays/countries/hungary.py index 5d9931711..0f0a977f6 100644 --- a/holidays/countries/hungary.py +++ b/holidays/countries/hungary.py @@ -9,16 +9,14 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td from gettext import gettext as tr from holidays.calendars.gregorian import DEC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, TUE_TO_PREV_MON, THU_TO_NEXT_FRI -class Hungary(HolidayBase, ChristianHolidays, InternationalHolidays): +class Hungary(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://en.wikipedia.org/wiki/Public_holidays_in_Hungary Codification dates: @@ -28,36 +26,35 @@ class Hungary(HolidayBase, ChristianHolidays, InternationalHolidays): country = "HU" default_language = "hu" + # Day off before + observed_label_before = tr("%s előtti pihenőnap") + # Day off after + observed_label = tr("%s utáni pihenőnap") supported_languages = ("en_US", "hu", "uk") - def _add_observed( - self, dt: date, since: int = 2010, before: bool = True, after: bool = True - ) -> None: - if not self.observed or dt.year < since: - return None - if self._is_tuesday(dt) and before: - # Day off before - self._add_holiday(self.tr("%s előtti pihenőnap") % self[dt], dt + td(days=-1)) - elif self._is_thursday(dt) and after: - # Day off after - self._add_holiday(self.tr("%s utáni pihenőnap") % self[dt], dt + td(days=+1)) - def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__( + observed_rule=TUE_TO_PREV_MON + THU_TO_NEXT_FRI, + observed_since=2010, + *args, + **kwargs, + ) def _populate(self, year): super()._populate(year) # New Year's Day. name = self.tr("Újév") - self._add_observed(self._add_new_years_day(name), before=False, since=2014) + jan_1 = self._add_new_years_day(name) + if year >= 2014: + self._add_observed(jan_1) - # The last day of the year is an observed day off if New Year's Day - # falls on a Tuesday. - if self.observed and self._is_monday(DEC, 31) and year >= 2014: - self._add_holiday_dec_31(self.tr("%s előtti pihenőnap") % name) + # The last day of the year is an observed day off if New Year's Day + # falls on a Tuesday. + if self.observed and self._is_monday(DEC, 31): + self._add_holiday_dec_31(self.tr(self.observed_label_before) % name) if 1945 <= year <= 1950 or year >= 1989: # National Day. @@ -111,12 +108,10 @@ def _populate(self, year): self._add_christmas_day(tr("Karácsony")) if year != 1955: - self._add_observed( - # Second Day of Christmas. - self._add_christmas_day_two(tr("Karácsony másnapja")), - since=2013, - before=False, - ) + # Second Day of Christmas. + dec_26 = self._add_christmas_day_two(tr("Karácsony másnapja")) + if year >= 2013: + self._add_observed(dec_26, rule=THU_TO_NEXT_FRI) # Soviet era. if 1950 <= year <= 1989: diff --git a/holidays/countries/ireland.py b/holidays/countries/ireland.py index f015d34a9..eb18624f1 100644 --- a/holidays/countries/ireland.py +++ b/holidays/countries/ireland.py @@ -9,15 +9,16 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.calendars.gregorian import FEB, MAR from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + SAT_SUN_TO_NEXT_MON, + SAT_SUN_TO_NEXT_MON_TUE, +) -class Ireland(HolidayBase, ChristianHolidays, InternationalHolidays): +class Ireland(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ Official holidays in Ireland, as declared in the Citizen's Information bulletin: @@ -25,6 +26,7 @@ class Ireland(HolidayBase, ChristianHolidays, InternationalHolidays): """ country = "IE" + observed_label = "%s (Observed)" special_holidays = { 2022: (MAR, 18, "Day of Remembrance and Recognition"), } @@ -32,13 +34,7 @@ class Ireland(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, days: int = +1) -> None: - if self.observed and self._is_weekend(dt): - self._add_holiday( - "%s (Observed)" % self[dt], dt + td(days=+2 if self._is_saturday(dt) else days) - ) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) @@ -81,7 +77,9 @@ def _populate(self, year): self._add_observed(self._add_christmas_day("Christmas Day")) # St. Stephen's Day. - self._add_observed(self._add_christmas_day_two("St. Stephen's Day"), days=+2) + self._add_observed( + self._add_christmas_day_two("St. Stephen's Day"), rule=SAT_SUN_TO_NEXT_MON_TUE + ) class IE(Ireland): diff --git a/holidays/countries/isle_of_man.py b/holidays/countries/isle_of_man.py index b9ccb82c8..6988f10a8 100644 --- a/holidays/countries/isle_of_man.py +++ b/holidays/countries/isle_of_man.py @@ -13,10 +13,9 @@ from datetime import timedelta as td from holidays.calendars.gregorian import JUL +from holidays.countries.united_kingdom import UnitedKingdom from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase - -from .united_kingdom import UnitedKingdom +from holidays.observed_holiday_base import ObservedHolidayBase, SAT_SUN_TO_NEXT_MON class IsleOfMan(UnitedKingdom): @@ -28,7 +27,7 @@ class IsleOfMan(UnitedKingdom): def __init__(self, *args, **kwargs): # Override UnitedKingdom __init__(). ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - HolidayBase.__init__(self, *args, **kwargs) + ObservedHolidayBase.__init__(self, observed_rule=SAT_SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year: int) -> None: super()._populate(year) diff --git a/holidays/countries/jamaica.py b/holidays/countries/jamaica.py index fbb57e580..9d40cc75d 100644 --- a/holidays/countries/jamaica.py +++ b/holidays/countries/jamaica.py @@ -9,33 +9,28 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + SUN_TO_NEXT_MON, + SUN_TO_NEXT_TUE, + SAT_SUN_TO_NEXT_MON, +) -class Jamaica(HolidayBase, ChristianHolidays, InternationalHolidays): +class Jamaica(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://en.wikipedia.org/wiki/Public_holidays_in_Jamaica https://www.mlss.gov.jm/wp-content/uploads/2017/11/The-Holidays-Public-General-Act.pdf """ country = "JM" + observed_label = "%s (Observed)" - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, include_sat: bool = False, days: int = +1) -> None: - if not self.observed: - return None - if self._is_sunday(dt) or (include_sat and self._is_saturday(dt)): - self._add_holiday( - "%s (Observed)" % self[dt], dt + td(days=+2 if self._is_saturday(dt) else days) - ) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) @@ -53,7 +48,9 @@ def _populate(self, year): self._add_easter_monday("Easter Monday") # National Labour Day - self._add_observed(self._add_holiday_may_23("National Labour Day"), include_sat=True) + self._add_observed( + self._add_holiday_may_23("National Labour Day"), rule=SAT_SUN_TO_NEXT_MON + ) # Emancipation Day if year >= 1998: @@ -66,7 +63,7 @@ def _populate(self, year): self._add_holiday_3rd_mon_of_oct("National Heroes Day") # Christmas Day - self._add_observed(self._add_christmas_day("Christmas Day"), days=+2) + self._add_observed(self._add_christmas_day("Christmas Day"), rule=SUN_TO_NEXT_TUE) # Boxing Day self._add_observed(self._add_christmas_day_two("Boxing Day")) diff --git a/holidays/countries/kazakhstan.py b/holidays/countries/kazakhstan.py index 711dd9489..0a2071ac9 100644 --- a/holidays/countries/kazakhstan.py +++ b/holidays/countries/kazakhstan.py @@ -9,14 +9,12 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import timedelta as td - from holidays.calendars.julian import JULIAN_CALENDAR -from holidays.groups import ChristianHolidays, IslamicHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.groups import ChristianHolidays, InternationalHolidays, IslamicHolidays +from holidays.observed_holiday_base import ObservedHolidayBase, SAT_SUN_TO_NEXT_WORKDAY -class Kazakhstan(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): +class Kazakhstan(ObservedHolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): """ 1. https://www.officeholidays.com/countries/kazakhstan/2020 2. https://egov.kz/cms/en/articles/holidays-calend @@ -25,12 +23,15 @@ class Kazakhstan(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicH """ country = "KZ" + observed_label = "%s (Observed)" def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self, JULIAN_CALENDAR) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__( + observed_rule=SAT_SUN_TO_NEXT_WORKDAY, observed_since=2002, *args, **kwargs + ) def _populate(self, year): # Kazakhstan declared its sovereignty on 25 October 1990 @@ -94,19 +95,13 @@ def _populate(self, year): if 2002 <= year <= 2021: dts_observed.add(self._add_holiday_dec_17(name)) + if self.observed: + self._populate_observed(dts_observed) + # Kurban Ait (nonworking day, without extending) if year >= 2006: self._add_eid_al_adha_day("Kurban Ait") - if self.observed and year >= 2002: - for dt in sorted(dts_observed): - if not self._is_weekend(dt): - continue - dt_observed = dt + td(days=+1) - while self._is_weekend(dt_observed) or dt_observed in dts_observed: - dt_observed += td(days=+1) - dts_observed.add(self._add_holiday("%s (Observed)" % self[dt], dt_observed)) - class KZ(Kazakhstan): pass diff --git a/holidays/countries/kenya.py b/holidays/countries/kenya.py index d4cf1a71d..02d455416 100644 --- a/holidays/countries/kenya.py +++ b/holidays/countries/kenya.py @@ -9,15 +9,12 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.calendars.gregorian import FEB, APR, AUG, SEP from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON, SUN_TO_NEXT_TUE -class Kenya(HolidayBase, ChristianHolidays, InternationalHolidays): +class Kenya(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://en.wikipedia.org/wiki/Public_holidays_in_Kenya http://kenyaembassyberlin.de/Public-Holidays-in-Kenya.48.0.html @@ -25,6 +22,7 @@ class Kenya(HolidayBase, ChristianHolidays, InternationalHolidays): """ country = "KE" + observed_label = "%s (Observed)" special_holidays = { 2020: (FEB, 11, "President Moi Celebration of Life Day"), 2022: ( @@ -40,20 +38,16 @@ class Kenya(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): - def _add_observed(dt: date, days: int = +1) -> None: - if self.observed and self._is_sunday(dt): - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=days)) - if year <= 1962: return None super()._populate(year) # New Year's Day - _add_observed(self._add_new_years_day("New Year's Day")) + self._add_observed(self._add_new_years_day("New Year's Day")) # Good Friday self._add_good_friday("Good Friday") @@ -62,31 +56,31 @@ def _add_observed(dt: date, days: int = +1) -> None: self._add_easter_monday("Easter Monday") # Labour Day - _add_observed(self._add_labor_day("Labour Day")) + self._add_observed(self._add_labor_day("Labour Day")) if year >= 2010: # Mandaraka Day - _add_observed(self._add_holiday_jun_1("Madaraka Day")) + self._add_observed(self._add_holiday_jun_1("Madaraka Day")) if 2002 <= year <= 2009 or year >= 2018: - _add_observed( + self._add_observed( # Utamaduni/Moi Day self._add_holiday_oct_10("Utamaduni Day" if year >= 2021 else "Moi Day") ) - _add_observed( + self._add_observed( # Mashuja/Kenyatta Day self._add_holiday_oct_20("Mashujaa Day" if year >= 2010 else "Kenyatta Day") ) # Jamhuri Day - _add_observed(self._add_holiday_dec_12("Jamhuri Day")) + self._add_observed(self._add_holiday_dec_12("Jamhuri Day")) # Christmas Day - _add_observed(self._add_christmas_day("Christmas Day"), days=+2) + self._add_observed(self._add_christmas_day("Christmas Day"), rule=SUN_TO_NEXT_TUE) # Boxing Day - _add_observed(self._add_christmas_day_two("Boxing Day")) + self._add_observed(self._add_christmas_day_two("Boxing Day")) class KE(Kenya): diff --git a/holidays/countries/latvia.py b/holidays/countries/latvia.py index c59b757c2..cd061b924 100644 --- a/holidays/countries/latvia.py +++ b/holidays/countries/latvia.py @@ -9,16 +9,15 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date from datetime import timedelta as td from gettext import gettext as tr from holidays.calendars.gregorian import MAY, JUL, SEP from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SAT_SUN_TO_NEXT_MON -class Latvia(HolidayBase, ChristianHolidays, InternationalHolidays): +class Latvia(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://en.wikipedia.org/wiki/Public_holidays_in_Latvia https://information.lv/ @@ -27,6 +26,8 @@ class Latvia(HolidayBase, ChristianHolidays, InternationalHolidays): country = "LV" default_language = "lv" + # %s (Observed). + observed_label = tr("%s (brīvdiena)") # General Latvian Song and Dance Festival closing day. song_and_dance_festival_closing_day = tr( @@ -57,14 +58,7 @@ class Latvia(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date) -> None: - if self.observed and self._is_weekend(dt): - self._add_holiday( - self.tr("%s (brīvdiena)") % self[dt], - dt + td(days=+2 if self._is_saturday(dt) else +1), - ) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): if year <= 1989: diff --git a/holidays/countries/liechtenstein.py b/holidays/countries/liechtenstein.py index b0dfae973..924a974a0 100644 --- a/holidays/countries/liechtenstein.py +++ b/holidays/countries/liechtenstein.py @@ -12,6 +12,7 @@ from gettext import gettext as tr +from holidays.constants import BANK, PUBLIC from holidays.groups import ChristianHolidays, InternationalHolidays from holidays.holiday_base import HolidayBase @@ -19,12 +20,14 @@ class Liechtenstein(HolidayBase, ChristianHolidays, InternationalHolidays): """ Liechtenstein holidays. - See https://en.wikipedia.org/wiki/Public_holidays_in_Liechtenstein - for details. + References: + - https://en.wikipedia.org/wiki/Public_holidays_in_Liechtenstein + - https://www.llb.li/en/contact/bank-holidays """ country = "LI" default_language = "de" + supported_categories = {BANK, PUBLIC} supported_languages = ("de", "en_US", "uk") def __init__(self, *args, **kwargs) -> None: @@ -32,30 +35,19 @@ def __init__(self, *args, **kwargs) -> None: InternationalHolidays.__init__(self) super().__init__(*args, **kwargs) - def _populate(self, year): - super()._populate(year) - + def _populate_public_holidays(self): # New Year's Day. self._add_new_years_day(tr("Neujahr")) - # Saint Berchtold's Day. - self._add_new_years_day_two(tr("Berchtoldstag")) - # Epiphany. self._add_epiphany_day(tr("Heilige Drei Könige")) # Candlemas. self._add_candlemas(tr("Mariä Lichtmess")) - # Shrove Tuesday. - self._add_carnival_tuesday(tr("Fasnachtsdienstag")) - # Saint Joseph's Day. self._add_saint_josephs_day(tr("Josefstag")) - # Good Friday. - self._add_good_friday(tr("Karfreitag")) - # Easter Sunday. self._add_easter_sunday(tr("Ostersonntag")) @@ -89,15 +81,25 @@ def _populate(self, year): # Immaculate Conception. self._add_immaculate_conception_day(tr("Mariä Empfängnis")) - # Christmas Eve. - self._add_christmas_eve(tr("Heiligabend")) - # Christmas Day. self._add_christmas_day(tr("Weihnachten")) # St. Stephen's Day. self._add_christmas_day_two(tr("Stefanstag")) + def _populate_bank_holidays(self): + # Saint Berchtold's Day. + self._add_new_years_day_two(tr("Berchtoldstag")) + + # Shrove Tuesday. + self._add_carnival_tuesday(tr("Fasnachtsdienstag")) + + # Good Friday. + self._add_good_friday(tr("Karfreitag")) + + # Christmas Eve. + self._add_christmas_eve(tr("Heiligabend")) + # New Year's Eve. self._add_new_years_eve(tr("Silvester")) diff --git a/holidays/countries/malawi.py b/holidays/countries/malawi.py index b35cf6249..436178548 100644 --- a/holidays/countries/malawi.py +++ b/holidays/countries/malawi.py @@ -9,31 +9,27 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + SAT_SUN_TO_NEXT_MON, + SAT_SUN_TO_NEXT_MON_TUE, +) -class Malawi(HolidayBase, ChristianHolidays, InternationalHolidays): +class Malawi(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://www.officeholidays.com/countries/malawi https://www.timeanddate.com/holidays/malawi/ """ country = "MW" + observed_label = "%s (Observed)" def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, days: int = +1) -> None: - if self.observed and self._is_weekend(dt): - self._add_holiday( - "%s (Observed)" % self[dt], dt + td(+2 if self._is_saturday(dt) else days) - ) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): # Observed since 2000 @@ -60,9 +56,9 @@ def _populate(self, year): self._add_observed(self._add_holiday_oct_15("Mother's Day")) - self._add_observed(self._add_christmas_day("Christmas Day"), days=+2) + self._add_observed(self._add_christmas_day("Christmas Day"), rule=SAT_SUN_TO_NEXT_MON_TUE) - self._add_observed(self._add_christmas_day_two("Boxing Day"), days=+2) + self._add_observed(self._add_christmas_day_two("Boxing Day"), rule=SAT_SUN_TO_NEXT_MON_TUE) class MW(Malawi): diff --git a/holidays/countries/malaysia.py b/holidays/countries/malaysia.py index 83591c19a..43347992c 100644 --- a/holidays/countries/malaysia.py +++ b/holidays/countries/malaysia.py @@ -9,8 +9,6 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import timedelta as td - from holidays.calendars import ( _CustomBuddhistCalendar, _CustomChineseCalendar, @@ -32,7 +30,6 @@ DEC, FRI, SAT, - SUN, ) from holidays.groups import ( BuddhistCalendarHolidays, @@ -42,11 +39,16 @@ InternationalHolidays, IslamicHolidays, ) -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + FRI_TO_NEXT_WORKDAY, + SAT_TO_NEXT_WORKDAY, + SUN_TO_NEXT_WORKDAY, +) class Malaysia( - HolidayBase, + ObservedHolidayBase, BuddhistCalendarHolidays, ChineseCalendarHolidays, ChristianHolidays, @@ -55,6 +57,7 @@ class Malaysia( IslamicHolidays, ): country = "MY" + observed_label = "%s [In lieu]" special_holidays = { # The years 1955 1959 1995 seems to have the elections # one weekday but I am not sure if they were marked as @@ -82,7 +85,7 @@ class Malaysia( "TRG", ) - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): """ An subclass of :py:class:`HolidayBase` representing public holidays in Malaysia. @@ -113,6 +116,13 @@ def __init__(self, *args, **kwargs) -> None: - Prior to 2021: holidays are not accurate. - 2027 and later: Thaipusam dates are are estimated, and so denoted. + Section 3 of Malaysian Holidays Act: + "If any day specified in the Schedule falls on Sunday then the day following shall be + a public holiday and if such day is already a public holiday, then the day following + shall be a public holiday". + In Johor and Kedah it's Friday -> Sunday, + in Kelantan and Terengganu it's Saturday -> Sunday + Reference: `Wikipedia `__ @@ -132,7 +142,7 @@ def __init__(self, *args, **kwargs) -> None: HinduCalendarHolidays.__init__(self, calendar=MalaysiaHinduCalendar()) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self, calendar=MalaysiaIslamicCalendar()) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=SUN_TO_NEXT_WORKDAY, *args, **kwargs) def _populate(self, year): super()._populate(year) @@ -307,36 +317,22 @@ def _populate(self, year): dts_observed.add(self._add_holiday_apr_26("Birthday of the Sultan of Terengganu")) - # Check for holidays that fall on a Sunday and - # implement Section 3 of Malaysian Holidays Act: - # "if any day specified in the Schedule falls on - # Sunday then the day following shall be a public - # holiday and if such day is already a public holiday, - # then the day following shall be a public holiday" - # In Johor and Kedah it's Friday -> Sunday, - # in Kelantan and Terengganu it's Saturday -> Sunday + if self.subdiv in {"JHR", "KDH"}: + self._observed_rule = FRI_TO_NEXT_WORKDAY + self.weekend = {FRI, SAT} + elif self.subdiv in {"KTN", "TRG"}: + self._observed_rule = SAT_TO_NEXT_WORKDAY + self.weekend = {FRI, SAT} + if self.observed: - weekday_observed_days = ( - (FRI, +2) - if self.subdiv in {"JHR", "KDH"} - else ((SAT, +1) if self.subdiv in {"KTN", "TRG"} else (SUN, +1)) - ) - for dt in sorted(dts_observed): - if dt and dt.weekday() != weekday_observed_days[0]: - continue - dt_in_lieu = dt + td(days=weekday_observed_days[1]) - while dt_in_lieu in dts_observed: - dt_in_lieu += td(days=+1) - for name in self.get_list(dt): - self._add_holiday(f"{name} [In lieu]", dt_in_lieu) - dts_observed.add(dt_in_lieu) + self._populate_observed(dts_observed) # Special cases observed from previous year. if year == 2007 and self.subdiv not in {"JHR", "KDH", "KTN", "TRG"}: - self._add_holiday_jan_2("Hari Raya Haji [In lieu]") + self._add_holiday_jan_2(self.observed_label % "Hari Raya Haji") if year == 2007 and self.subdiv == "TRG": - self._add_holiday_jan_2("Arafat Day [In lieu]") + self._add_holiday_jan_2(self.observed_label % "Arafat Day") # The last two days in May (Pesta Kaamatan). # (Sarawak Act) diff --git a/holidays/countries/marshall_islands.py b/holidays/countries/marshall_islands.py index 1bc0015a1..a6b93b4f0 100644 --- a/holidays/countries/marshall_islands.py +++ b/holidays/countries/marshall_islands.py @@ -10,23 +10,20 @@ # License: MIT (see LICENSE file) import warnings -from datetime import date -from datetime import timedelta as td from holidays.calendars.gregorian import NOV from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class HolidaysMH(HolidayBase, ChristianHolidays, InternationalHolidays): +class HolidaysMH(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://rmiparliament.org/cms/component/content/article/14-pressrelease/49-important-public-holidays.html?Itemid=101 https://www.rmiembassyus.org/country-profile#:~:text=national%20holidays """ country = "MH" - - # Special Holidays + observed_label = "%s Holiday" # General Election Day election_day = "General Election Day" @@ -42,17 +39,10 @@ class HolidaysMH(HolidayBase, ChristianHolidays, InternationalHolidays): 2023: (NOV, 20, election_day), } - def _add_observed(self, dt: date) -> None: - """ - If fall on Sunday, an observed holiday marked with suffix " Holiday" will be added. - """ - if self.observed and self._is_sunday(dt): - self._add_holiday("%s Holiday" % self[dt], dt + td(days=+1)) - def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) diff --git a/holidays/countries/monaco.py b/holidays/countries/monaco.py index 14f1eb33d..3131a8d3c 100644 --- a/holidays/countries/monaco.py +++ b/holidays/countries/monaco.py @@ -9,16 +9,14 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td from gettext import gettext as tr from holidays.calendars.gregorian import JAN, DEC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class Monaco(HolidayBase, ChristianHolidays, InternationalHolidays): +class Monaco(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://en.wikipedia.org/wiki/Public_holidays_in_Monaco https://en.service-public-entreprises.gouv.mc/Employment-and-social-affairs/Employment-regulations/Leave/Public-Holidays # noqa: E501 @@ -26,17 +24,16 @@ class Monaco(HolidayBase, ChristianHolidays, InternationalHolidays): country = "MC" default_language = "fr" + # %s (Observed). + observed_label = tr("%s (Observé)") + # Public holiday. special_holidays = {2015: (JAN, 7, tr("Jour férié"))} supported_languages = ("en_US", "fr", "uk") def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, days: int = +1) -> None: - if self.observed and self._is_sunday(dt): - self._add_holiday(self.tr("%s (Observé)") % self[dt], dt + td(days=days)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) diff --git a/holidays/countries/montenegro.py b/holidays/countries/montenegro.py index 9a212f487..37161eeb5 100644 --- a/holidays/countries/montenegro.py +++ b/holidays/countries/montenegro.py @@ -9,15 +9,12 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.calendars.julian import JULIAN_CALENDAR from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON, SUN_TO_NEXT_TUE -class Montenegro(HolidayBase, ChristianHolidays, InternationalHolidays): +class Montenegro(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Montenegro @@ -27,22 +24,19 @@ class Montenegro(HolidayBase, ChristianHolidays, InternationalHolidays): """ country = "ME" + observed_label = "%s (Observed)" def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self, calendar=JULIAN_CALENDAR) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, days: int = +1) -> None: - if self.observed and self._is_sunday(dt): - self._add_holiday("%s (Observed)" % self[dt], dt + td(days)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) # New Year's Day. name = "New Year's Day" - self._add_observed(self._add_new_years_day(name), days=+2) + self._add_observed(self._add_new_years_day(name), rule=SUN_TO_NEXT_TUE) self._add_observed(self._add_new_years_day_two(name)) # Orthodox Christmas Eve. @@ -53,7 +47,7 @@ def _populate(self, year): # Labour Day. name = "Labour Day" - self._add_observed(self._add_labor_day(name), days=+2) + self._add_observed(self._add_labor_day(name), rule=SUN_TO_NEXT_TUE) self._add_observed(self._add_labor_day_two(name)) # Good Friday. @@ -67,15 +61,13 @@ def _populate(self, year): # Independence Day. name = "Independence Day" - may_21 = self._add_holiday_may_21(name) - self._add_observed(may_21, days=+2) - self._add_observed(self._add_holiday(name, may_21 + td(days=+1))) + self._add_observed(self._add_holiday_may_21(name), rule=SUN_TO_NEXT_TUE) + self._add_observed(self._add_holiday_may_22(name)) # Statehood Day. name = "Statehood Day" - jul_13 = self._add_holiday_jul_13(name) - self._add_observed(jul_13, days=+2) - self._add_observed(self._add_holiday(name, jul_13 + td(days=+1))) + self._add_observed(self._add_holiday_jul_13(name), rule=SUN_TO_NEXT_TUE) + self._add_observed(self._add_holiday_jul_14(name)) class ME(Montenegro): diff --git a/holidays/countries/mozambique.py b/holidays/countries/mozambique.py index b9bfe8a5a..58db11d12 100644 --- a/holidays/countries/mozambique.py +++ b/holidays/countries/mozambique.py @@ -9,32 +9,23 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td from gettext import gettext as tr from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class Mozambique(HolidayBase, ChristianHolidays, InternationalHolidays): +class Mozambique(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): country = "MZ" default_language = "pt_MZ" + # %s (Observed). + observed_label = tr("%s (Ponte)") supported_languages = ("en_US", "pt_MZ", "uk") def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date) -> None: - """ - Whenever a public holiday falls on a Sunday, - it rolls over to the following Monday. - """ - if self.observed and self._is_sunday(dt): - # %s (Observed). - self._add_holiday(self.tr("%s (Ponte)") % self[dt], dt + td(days=+1)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): if year <= 1974: diff --git a/holidays/countries/namibia.py b/holidays/countries/namibia.py index 9de2f3f14..ed8bc51f4 100644 --- a/holidays/countries/namibia.py +++ b/holidays/countries/namibia.py @@ -9,22 +9,26 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - -from holidays.calendars.gregorian import JAN, FEB, DEC +from holidays.calendars.gregorian import JAN, DEC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class Namibia(HolidayBase, ChristianHolidays, InternationalHolidays): +class Namibia(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://www.officeholidays.com/countries/namibia https://www.timeanddate.com/holidays/namibia/ + https://tinyurl.com/lacorg5835 + As of 1991/2/1, whenever a public holiday falls on a Sunday, it rolls over to the monday, + unless that monday is already a public holiday. + Since the interval from 1991/1/1 to 1991/2/1 includes only New Year's Day, and it's a Tuesday, + we can assume that the beginning is 1991. """ country = "NA" + # %s (Observed). + observed_label = "%s (Observed)" special_holidays = { # https://gazettes.africa/archive/na/1999/na-government-gazette-dated-1999-11-22-no-2234.pdf 1999: (DEC, 31, "Y2K changeover"), @@ -34,15 +38,7 @@ class Namibia(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date) -> None: - # https://tinyurl.com/lacorg5835 - # As of 1991/2/1, whenever a public holiday falls on a Sunday, - # it rolls over to the monday, unless that monday is already - # a public holiday. - if self.observed and self._is_sunday(dt) and dt >= date(1991, FEB, 1): - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=+1)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, observed_since=1991, *args, **kwargs) def _populate(self, year): if year <= 1989: diff --git a/holidays/countries/new_zealand.py b/holidays/countries/new_zealand.py index dc87cba27..ff5f7988f 100644 --- a/holidays/countries/new_zealand.py +++ b/holidays/countries/new_zealand.py @@ -12,24 +12,19 @@ from datetime import date from datetime import timedelta as td -from holidays.calendars.gregorian import ( - JAN, - FEB, - MAR, - JUN, - JUL, - SEP, - NOV, - DEC, - MON, - _get_nth_weekday_from, -) +from holidays.calendars.gregorian import JAN, FEB, MAR, JUN, JUL, SEP, NOV, DEC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + ALL_TO_NEAREST_MON, + SAT_SUN_TO_NEXT_MON, + SAT_SUN_TO_NEXT_MON_TUE, +) -class NewZealand(HolidayBase, ChristianHolidays, InternationalHolidays): +class NewZealand(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): country = "NZ" + observed_label = "%s (Observed)" special_holidays = { 2022: (SEP, 26, "Queen Elizabeth II Memorial Day"), } @@ -78,20 +73,12 @@ class NewZealand(HolidayBase, ChristianHolidays, InternationalHolidays): def _get_nearest_monday(self, *args) -> date: dt = args if len(args) > 1 else args[0] dt = dt if isinstance(dt, date) else date(self._year, *dt) - return _get_nth_weekday_from( - +1 if self._is_friday(dt) or self._is_weekend(dt) else -1, MON, dt - ) - - def _add_observed(self, dt: date, days: int = +1) -> None: - if self.observed and self._is_weekend(dt): - self._add_holiday( - "%s (Observed)" % self[dt], dt + td(days=+2 if self._is_saturday(dt) else days) - ) + return self._get_observed_date(dt, rule=ALL_TO_NEAREST_MON) def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): # Bank Holidays Act 1873 @@ -111,8 +98,10 @@ def _populate(self, year): super()._populate(year) # New Year's Day - self._add_observed(self._add_new_years_day("New Year's Day"), days=+2) - self._add_observed(self._add_new_years_day_two("Day after New Year's Day"), days=+2) + self._add_observed(self._add_new_years_day("New Year's Day"), rule=SAT_SUN_TO_NEXT_MON_TUE) + self._add_observed( + self._add_new_years_day_two("Day after New Year's Day"), rule=SAT_SUN_TO_NEXT_MON_TUE + ) # Waitangi Day if year >= 1974: @@ -194,10 +183,10 @@ def _populate(self, year): self._add_holiday_2nd_wed_of_oct(name) # Christmas Day - self._add_observed(self._add_christmas_day("Christmas Day"), days=+2) + self._add_observed(self._add_christmas_day("Christmas Day"), rule=SAT_SUN_TO_NEXT_MON_TUE) # Boxing Day - self._add_observed(self._add_christmas_day_two("Boxing Day"), days=+2) + self._add_observed(self._add_christmas_day_two("Boxing Day"), rule=SAT_SUN_TO_NEXT_MON_TUE) if self.subdiv == "Auckland": self._add_subdiv_auk_holidays() diff --git a/holidays/countries/nigeria.py b/holidays/countries/nigeria.py index cedfbdeb2..01c4b8bb2 100644 --- a/holidays/countries/nigeria.py +++ b/holidays/countries/nigeria.py @@ -9,19 +9,18 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import timedelta as td - from holidays.calendars.gregorian import FEB, MAY -from holidays.groups import ChristianHolidays, IslamicHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.groups import ChristianHolidays, InternationalHolidays, IslamicHolidays +from holidays.observed_holiday_base import ObservedHolidayBase, SAT_SUN_TO_NEXT_WORKDAY -class Nigeria(HolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): +class Nigeria(ObservedHolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): """ https://en.wikipedia.org/wiki/Public_holidays_in_Nigeria """ country = "NG" + observed_label = "%s (Observed)" special_holidays = { 2019: ( (FEB, 22, "Public Holiday for Elections"), @@ -33,7 +32,9 @@ def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__( + observed_rule=SAT_SUN_TO_NEXT_WORKDAY, observed_since=2016, *args, **kwargs + ) def _populate(self, year): if year <= 1978: @@ -79,16 +80,8 @@ def _populate(self, year): # Birthday of Prophet Muhammad. dts_observed.update(self._add_mawlid_day("Eid-el-Mawlid")) - # Observed holidays. - if self.observed and year >= 2016: - for dt in sorted(dts_observed): - if not self._is_weekend(dt): - continue - dt_observed = dt + td(days=+1) - while self._is_weekend(dt_observed) or dt_observed in dts_observed: - dt_observed += td(days=+1) - for name in self.get_list(dt): - dts_observed.add(self._add_holiday("%s (Observed)" % name, dt_observed)) + if self.observed: + self._populate_observed(dts_observed) class NG(Nigeria): diff --git a/holidays/countries/panama.py b/holidays/countries/panama.py index 125a4b328..7a402bc8f 100644 --- a/holidays/countries/panama.py +++ b/holidays/countries/panama.py @@ -9,14 +9,11 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class Panama(HolidayBase, ChristianHolidays, InternationalHolidays): +class Panama(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Panama @@ -24,15 +21,12 @@ class Panama(HolidayBase, ChristianHolidays, InternationalHolidays): """ country = "PA" + observed_label = "%s (Observed)" def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date) -> None: - if self.observed and self._is_sunday(dt): - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=+1)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) diff --git a/holidays/countries/saudi_arabia.py b/holidays/countries/saudi_arabia.py index 5853482ec..31319c588 100644 --- a/holidays/countries/saudi_arabia.py +++ b/holidays/countries/saudi_arabia.py @@ -16,10 +16,18 @@ from holidays.calendars.gregorian import FEB, SEP, NOV, THU, FRI, SAT from holidays.groups import IslamicHolidays -from holidays.holiday_base import HolidayBase - - -class SaudiArabia(HolidayBase, IslamicHolidays): +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + THU_TO_PREV_WED, + FRI_TO_PREV_THU, + FRI_TO_NEXT_SAT, + SAT_TO_NEXT_SUN, + THU_FRI_TO_NEXT_WORKDAY, + FRI_SAT_TO_NEXT_WORKDAY, +) + + +class SaudiArabia(ObservedHolidayBase, IslamicHolidays): """ There are only 4 official national holidays in Saudi: https://laboreducation.hrsd.gov.sa/en/gallery/274 @@ -49,35 +57,16 @@ class SaudiArabia(HolidayBase, IslamicHolidays): def __init__(self, *args, **kwargs): IslamicHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=FRI_TO_PREV_THU + SAT_TO_NEXT_SUN, *args, **kwargs) def _add_islamic_observed(self, dts: Set[date]) -> None: # Observed days are added to make up for any days falling on a weekend. if not self.observed: return None - + observed_rule = THU_FRI_TO_NEXT_WORKDAY if self._year <= 2012 else FRI_SAT_TO_NEXT_WORKDAY for dt in dts: for i in range(4): - if not self._is_weekend(dt + td(days=-i)): - continue - dt_observed = dt + td(days=+1) - while dt_observed.year == self._year and ( - self._is_weekend(dt_observed) or dt_observed in self - ): - dt_observed += td(days=+1) - self._add_holiday(self.tr(self.observed_label) % self[dt], dt_observed) - - def _add_observed(self, dt: date) -> None: - if not self.observed: - return None - - weekend = sorted(self.weekend) - # 1st weekend day (Thursday before 2013 and Friday otherwise) - if dt.weekday() == weekend[0]: - self._add_holiday(self.tr(self.observed_label) % self.tr(self[dt]), dt + td(days=-1)) - # 2nd weekend day (Friday before 2013 and Saturday otherwise) - elif dt.weekday() == weekend[1]: - self._add_holiday(self.tr(self.observed_label) % self.tr(self[dt]), dt + td(days=+1)) + self._add_observed(dt + td(days=-i), name=self[dt], rule=observed_rule) def _populate(self, year): super()._populate(year) @@ -85,6 +74,11 @@ def _populate(self, year): # Weekend used to be THU, FRI before June 28th, 2013. # On that year both Eids were after that date, and Founding day # holiday started at 2022; so what below works. + self._observed_rule = ( + THU_TO_PREV_WED + FRI_TO_NEXT_SAT + if year <= 2012 + else FRI_TO_PREV_THU + SAT_TO_NEXT_SUN + ) self.weekend = {THU, FRI} if year <= 2012 else {FRI, SAT} # Eid al-Fitr Holiday @@ -103,7 +97,7 @@ def _populate(self, year): self._add_islamic_observed(self._add_eid_al_adha_day_three(name)) # If National Day happens within the Eid al-Fitr Holiday or - # within Eid al-Adha Holiday, there is no extra holidays given for it. + # Eid al-Adha Holiday, there is no extra holidays given for it. if year >= 2005: dt = date(year, SEP, 23) if dt not in self: @@ -111,7 +105,7 @@ def _populate(self, year): self._add_observed(self._add_holiday(tr("اليوم الوطني"), dt)) # If Founding Day happens within the Eid al-Fitr Holiday or - # within Eid al-Adha Holiday, there is no extra holidays given for it. + # Eid al-Adha Holiday, there is no extra holidays given for it. if year >= 2022: dt = date(year, FEB, 22) if dt not in self: diff --git a/holidays/countries/serbia.py b/holidays/countries/serbia.py index b83cabd7b..6881235e8 100644 --- a/holidays/countries/serbia.py +++ b/holidays/countries/serbia.py @@ -9,16 +9,14 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td from gettext import gettext as tr from holidays.calendars.julian import JULIAN_CALENDAR from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON, SUN_TO_NEXT_TUE -class Serbia(HolidayBase, ChristianHolidays, InternationalHolidays): +class Serbia(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ Serbia holidays. @@ -28,23 +26,21 @@ class Serbia(HolidayBase, ChristianHolidays, InternationalHolidays): country = "RS" default_language = "sr" + # %s (Observed). + observed_label = tr("%s (слободан дан)") supported_languages = ("en_US", "sr") def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self, JULIAN_CALENDAR) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, days: int = +1) -> None: - if self.observed and self._is_sunday(dt): - self._add_holiday(self.tr("%s (слободан дан)") % self[dt], dt + td(days)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) # New Year's Day. name = tr("Нова година") - self._add_observed(self._add_new_years_day(name), days=+2) + self._add_observed(self._add_new_years_day(name), rule=SUN_TO_NEXT_TUE) self._add_observed(self._add_new_years_day_two(name)) # Orthodox Christmas. @@ -52,14 +48,17 @@ def _populate(self, year): # Statehood Day. name = tr("Дан државности Србије") - self._add_observed(self._add_holiday_feb_15(name), days=+2) + self._add_observed(self._add_holiday_feb_15(name), rule=SUN_TO_NEXT_TUE) self._add_observed(self._add_holiday_feb_16(name)) # International Workers' Day. name = tr("Празник рада") - self._add_observed(self._add_labor_day(name), days=+2) - may_2 = self._add_labor_day_two(name) - self._add_observed(may_2, days=+2 if may_2 == self._easter_sunday else +1) + self._add_observed(self._add_labor_day(name), rule=SUN_TO_NEXT_TUE) + + self._add_observed( + may_2 := self._add_labor_day_two(name), + rule=SUN_TO_NEXT_TUE if may_2 == self._easter_sunday else SUN_TO_NEXT_MON, + ) # Armistice Day. self._add_observed(self._add_remembrance_day(tr("Дан примирја у Првом светском рату"))) diff --git a/holidays/countries/singapore.py b/holidays/countries/singapore.py index a7269004e..6e3479f17 100644 --- a/holidays/countries/singapore.py +++ b/holidays/countries/singapore.py @@ -9,8 +9,6 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import timedelta as td - from holidays.calendars import ( _CustomBuddhistCalendar, _CustomChineseCalendar, @@ -26,11 +24,11 @@ InternationalHolidays, IslamicHolidays, ) -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_WORKDAY class Singapore( - HolidayBase, + ObservedHolidayBase, BuddhistCalendarHolidays, ChineseCalendarHolidays, ChristianHolidays, @@ -39,6 +37,7 @@ class Singapore( IslamicHolidays, ): country = "SG" + observed_label = "%s (Observed)" special_holidays = { 2001: (NOV, 3, "Polling Day"), 2006: (MAY, 6, "Polling Day"), @@ -56,7 +55,7 @@ class Singapore( 2023: (SEP, 1, "Polling Day"), } - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): """ A subclass of :py:class:`HolidayBase` representing public holidays in Singapore. @@ -100,27 +99,31 @@ def __init__(self, *args, **kwargs) -> None: HinduCalendarHolidays.__init__(self, calendar=SingaporeHinduCalendar()) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self, calendar=SingaporeIslamicCalendar()) - super().__init__(*args, **kwargs) + # Implement Section 4(2) of the Holidays Act: + # "if any day specified in the Schedule falls on a Sunday, + # the day next following not being itself a public holiday + # is declared a public holiday in Singapore." + super().__init__(observed_rule=SUN_TO_NEXT_WORKDAY, observed_since=1998, *args, **kwargs) def _populate(self, year) -> None: super()._populate(year) - observed_dates = set() + dts_observed = set() # New Year's Day - observed_dates.add(self._add_new_years_day("New Year's Day")) + dts_observed.add(self._add_new_years_day("New Year's Day")) # Chinese New Year (two days) name = "Chinese New Year" - observed_dates.add(self._add_chinese_new_years_day(name)) # type: ignore[arg-type] - observed_dates.add(self._add_chinese_new_years_day_two(name)) # type: ignore[arg-type] + dts_observed.add(self._add_chinese_new_years_day(name)) # type: ignore[arg-type] + dts_observed.add(self._add_chinese_new_years_day_two(name)) # type: ignore[arg-type] # Hari Raya Puasa (Eid al-Fitr) - observed_dates.update(self._add_eid_al_fitr_day("Hari Raya Puasa")) + dts_observed.update(self._add_eid_al_fitr_day("Hari Raya Puasa")) if year <= 1968: self._add_eid_al_fitr_day_two("Second day of Hari Raya Puasa") # Hari Raya Haji (Eid al-Adha) - observed_dates.update(self._add_eid_al_adha_day("Hari Raya Haji")) + dts_observed.update(self._add_eid_al_adha_day("Hari Raya Haji")) # Good Friday self._add_good_friday("Good Friday") @@ -133,42 +136,30 @@ def _populate(self, year) -> None: self._add_easter_monday("Easter Monday") # Labour Day - observed_dates.add(self._add_labor_day("Labour Day")) + dts_observed.add(self._add_labor_day("Labour Day")) # Vesak Day - observed_dates.add(self._add_vesak("Vesak Day")) # type: ignore[arg-type] + dts_observed.add(self._add_vesak("Vesak Day")) # type: ignore[arg-type] # National Day - observed_dates.add(self._add_holiday_aug_9("National Day")) + dts_observed.add(self._add_holiday_aug_9("National Day")) # Deepavali (Diwali) - observed_dates.add(self._add_diwali("Deepavali")) # type: ignore[arg-type] + dts_observed.add(self._add_diwali("Deepavali")) # type: ignore[arg-type] # Christmas Day - observed_dates.add(self._add_christmas_day("Christmas Day")) + dts_observed.add(self._add_christmas_day("Christmas Day")) # Boxing day (up to and including 1968) if year <= 1968: self._add_christmas_day_two("Boxing Day") - # Implement Section 4(2) of the Holidays Act: - # "if any day specified in the Schedule falls on a Sunday, - # the day next following not being itself a public holiday - # is declared a public holiday in Singapore." - if not self.observed: - return None - if year >= 1998: - for dt in sorted(observed_dates): - if not self._is_sunday(dt): - continue - self._add_holiday( - "%s (Observed)" % self[dt], - dt + td(days=2 if dt + td(days=+1) in observed_dates else 1), - ) - - # special case (observed from previous year) - if year == 2007: - self._add_holiday_jan_2("Hari Raya Haji (Observed)") + if self.observed: + self._populate_observed(dts_observed) + + # Observed holidays special cases (observed from previous year) + if year == 2007: + self._add_holiday_jan_2(self.observed_label % "Hari Raya Haji") class SG(Singapore): diff --git a/holidays/countries/south_africa.py b/holidays/countries/south_africa.py index 749357d0e..a6ca66191 100644 --- a/holidays/countries/south_africa.py +++ b/holidays/countries/south_africa.py @@ -9,21 +9,19 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.calendars.gregorian import JAN, MAR, APR, MAY, JUN, AUG, NOV, DEC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class SouthAfrica(HolidayBase, ChristianHolidays, InternationalHolidays): +class SouthAfrica(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ http://www.gov.za/about-sa/public-holidays https://en.wikipedia.org/wiki/Public_holidays_in_South_Africa """ country = "ZA" + observed_label = "%s (Observed)" special_holidays = { 1999: ( (JUN, 2, "National and provincial government elections"), @@ -51,13 +49,7 @@ class SouthAfrica(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date) -> None: - # As of 1995/1/1, whenever a public holiday falls on a Sunday, - # it rolls over to the following Monday - if self.observed and self._is_sunday(dt) and self._year >= 1995: - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=+1)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, observed_since=1995, *args, **kwargs) def _populate(self, year): # Observed since 1910, with a few name changes diff --git a/holidays/countries/spain.py b/holidays/countries/spain.py index 2aedc4152..267839652 100644 --- a/holidays/countries/spain.py +++ b/holidays/countries/spain.py @@ -9,21 +9,18 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td -from typing import Optional - from holidays.groups import ChristianHolidays, IslamicHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class Spain(HolidayBase, ChristianHolidays, IslamicHolidays, InternationalHolidays): +class Spain(ObservedHolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays): """ References: - https://administracion.gob.es/pag_Home/atencionCiudadana/calendarios.html """ country = "ES" + observed_label = "%s (Trasladado)" subdivisions = ( "AN", "AR", @@ -50,17 +47,8 @@ def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) IslamicHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_holiday(self, name: str, dt: date) -> Optional[date]: - if dt.year != self._year: - return None - if self.observed and self._is_sunday(dt): - dt += td(days=+1) - name = self.tr("%s (Trasladado)") % self.tr(name) - - return super()._add_holiday(self.tr(name), dt) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) @@ -93,35 +81,35 @@ def _populate(self, year): def _add_subdiv_an_holidays(self): if self._year == 2023: - self._add_new_years_day("Año nuevo") + self._add_observed(self._add_new_years_day("Año nuevo")) self._add_holiday_feb_28("Día de Andalucia") if self._year <= 2022: self._add_holy_thursday("Jueves Santo") if self._year == 2022: - self._add_labor_day("Día del Trabajador") - self._add_christmas_day("Navidad") + self._add_observed(self._add_labor_day("Día del Trabajador")) + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_ar_holidays(self): if self._year == 2023: - self._add_new_years_day("Año nuevo") + self._add_observed(self._add_new_years_day("Año nuevo")) if self._year <= 2014: self._add_saint_josephs_day("San José") if self._year <= 2022: self._add_holy_thursday("Jueves Santo") self._add_saint_georges_day("Día de San Jorge") if self._year == 2022: - self._add_labor_day("Día del Trabajador") - self._add_christmas_day("Navidad") + self._add_observed(self._add_labor_day("Día del Trabajador")) + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_as_holidays(self): if self._year == 2023: - self._add_new_years_day("Año nuevo") + self._add_observed(self._add_new_years_day("Año nuevo")) if self._year <= 2022: self._add_holy_thursday("Jueves Santo") self._add_holiday_sep_8("Día de Asturias") if self._year == 2022: - self._add_labor_day("Día del Trabajador") - self._add_christmas_day("Navidad") + self._add_observed(self._add_labor_day("Día del Trabajador")) + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_cb_holidays(self): if self._year <= 2022: @@ -129,7 +117,7 @@ def _add_subdiv_cb_holidays(self): self._add_holiday_jul_28("Día de las Instituciones de Cantabria") self._add_holiday_sep_15("Día de la Bien Aparecida") if self._year == 2022: - self._add_christmas_day("Navidad") + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_ce_holidays(self): if self._year <= 2022: @@ -143,7 +131,7 @@ def _add_subdiv_ce_holidays(self): def _add_subdiv_cl_holidays(self): if self._year == 2023: - self._add_new_years_day("Año nuevo") + self._add_observed(self._add_new_years_day("Año nuevo")) self._add_saint_james_day("Día de Santiago Apóstol") if self._year <= 2014: self._add_saint_josephs_day("San José") @@ -151,8 +139,8 @@ def _add_subdiv_cl_holidays(self): self._add_holy_thursday("Jueves Santo") self._add_holiday_apr_23("Día de Castilla y Leon") if self._year == 2022: - self._add_labor_day("Día del Trabajador") - self._add_christmas_day("Navidad") + self._add_observed(self._add_labor_day("Día del Trabajador")) + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_cm_holidays(self): if self._year <= 2015 or 2020 <= self._year <= 2021: @@ -165,14 +153,14 @@ def _add_subdiv_cm_holidays(self): self._add_corpus_christi_day("Corpus Christi") self._add_holiday_may_31("Día de Castilla La Mancha") if self._year == 2022: - self._add_christmas_day("Navidad") + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_cn_holidays(self): if self._year <= 2022: self._add_holy_thursday("Jueves Santo") self._add_holiday_may_30("Día de Canarias") if self._year == 2022: - self._add_christmas_day("Navidad") + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_ct_holidays(self): self._add_easter_monday("Lunes de Pascua") @@ -193,12 +181,12 @@ def _add_subdiv_ex_holidays(self): if self._year == 2023: self._add_carnival_tuesday("Carnaval") if self._year == 2022: - self._add_labor_day("Día del Trabajador") - self._add_christmas_day("Navidad") + self._add_observed(self._add_labor_day("Día del Trabajador")) + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_ga_holidays(self): if self._year <= 2014 or 2018 <= self._year <= 2021: - self._add_saint_josephs_day("San José") + self._add_observed(self._add_saint_josephs_day("San José")) if self._year <= 2022: self._add_holy_thursday("Jueves Santo") if self._year >= 2022: @@ -213,32 +201,32 @@ def _add_subdiv_ib_holidays(self): self._add_holy_thursday("Jueves Santo") self._add_easter_monday("Lunes de Pascua") if self._year == 2022: - self._add_christmas_day("Navidad") + self._add_observed(self._add_christmas_day("Navidad")) if self._year <= 2020: self._add_christmas_day_two("San Esteban") def _add_subdiv_mc_holidays(self): if self._year == 2023: - self._add_new_years_day("Año nuevo") + self._add_observed(self._add_new_years_day("Año nuevo")) if self._year <= 2021 and self._year != 2017: - self._add_saint_josephs_day("San José") + self._add_observed(self._add_saint_josephs_day("San José")) if self._year <= 2022: self._add_holy_thursday("Jueves Santo") if self._year == 2022: - self._add_labor_day("Día del Trabajador") + self._add_observed(self._add_labor_day("Día del Trabajador")) self._add_holiday_jun_9("Día de la Región de Murcia") if self._year == 2022: - self._add_christmas_day("Navidad") + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_md_holidays(self): if self._year <= 2015 or self._year == 2023: - self._add_saint_josephs_day("San José") + self._add_observed(self._add_saint_josephs_day("San José")) if self._year <= 2022: self._add_holy_thursday("Jueves Santo") self._add_holiday_may_2("Día de Comunidad de Madrid") if self._year == 2022: self._add_saint_james_day("Día de Santiago Apóstol") - self._add_christmas_day("Navidad") + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_ml_holidays(self): if self._year <= 2016: @@ -250,7 +238,7 @@ def _add_subdiv_ml_holidays(self): if self._year == 2022: self._add_eid_al_fitr_day_two("Eid al-Fitr") self._add_eid_al_adha_day_three("Eid al-Adha") - self._add_christmas_day("Navidad") + self._add_observed(self._add_christmas_day("Navidad")) elif self._year == 2023: self._add_eid_al_fitr_day("Eid al-Fitr") self._add_eid_al_adha_day_two("Eid al-Adha") @@ -264,7 +252,7 @@ def _add_subdiv_nc_holidays(self): if self._year >= 2022: self._add_saint_james_day("Día de Santiago Apóstol") if self._year == 2022: - self._add_christmas_day("Navidad") + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_pv_holidays(self): if self._year <= 2021: @@ -286,7 +274,7 @@ def _add_subdiv_ri_holidays(self): self._add_easter_monday("Lunes de Pascua") self._add_holiday_jun_9("Día de La Rioja") if self._year == 2022: - self._add_christmas_day("Navidad") + self._add_observed(self._add_christmas_day("Navidad")) def _add_subdiv_vc_holidays(self): if self._year <= 2022 and self._year != 2017: diff --git a/holidays/countries/taiwan.py b/holidays/countries/taiwan.py index 569ca1def..d2c4b8ced 100644 --- a/holidays/countries/taiwan.py +++ b/holidays/countries/taiwan.py @@ -9,14 +9,16 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import timedelta as td - from holidays.calendars.gregorian import DEC from holidays.groups import ChineseCalendarHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + SAT_TO_PREV_WORKDAY, + SUN_TO_NEXT_WORKDAY, +) -class Taiwan(HolidayBase, ChineseCalendarHolidays, InternationalHolidays): +class Taiwan(ObservedHolidayBase, ChineseCalendarHolidays, InternationalHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Taiwan @@ -28,11 +30,17 @@ class Taiwan(HolidayBase, ChineseCalendarHolidays, InternationalHolidays): """ country = "TW" + observed_label = "%s (Observed)" def __init__(self, *args, **kwargs): ChineseCalendarHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__( + observed_rule=SAT_TO_PREV_WORKDAY + SUN_TO_NEXT_WORKDAY, + observed_since=2015, + *args, + **kwargs, + ) def _populate(self, year): if year <= 1911: @@ -45,8 +53,8 @@ def _populate(self, year): name = "Republic of China Founding Day / New Year's Day" dts_observed.add(self._add_new_years_day(name)) - if self.observed and year >= 2015 and self._is_friday(DEC, 31): - self._add_holiday_dec_31("%s (Observed)" % name) + if self.observed and self._is_friday(DEC, 31) and year >= 2015: + self._add_holiday_dec_31(self.observed_label % name) # Lunar New Year. self._add_chinese_new_years_eve("Lunar New Year's Eve") @@ -84,16 +92,8 @@ def _populate(self, year): # National Day. dts_observed.add(self._add_holiday_oct_10("National Day")) - if self.observed and year >= 2015: - for dt in sorted(dts_observed): - if not self._is_weekend(dt): - continue - delta = -1 if self._is_saturday(dt) else +1 - for name in self.get_list(dt): - dt_observed = dt + td(days=delta) - while dt_observed in dts_observed: - dt_observed += td(days=delta) - dts_observed.add(self._add_holiday("%s (Observed)" % name, dt_observed)) + if self.observed: + self._populate_observed(dts_observed, multiple=True) class TW(Taiwan): diff --git a/holidays/countries/thailand.py b/holidays/countries/thailand.py index 06b566e67..9ef2f7193 100644 --- a/holidays/countries/thailand.py +++ b/holidays/countries/thailand.py @@ -10,15 +10,23 @@ # License: MIT (see LICENSE file) from datetime import date -from datetime import timedelta as td from gettext import gettext as tr from holidays.calendars.gregorian import JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC +from holidays.constants import ARMED_FORCES, BANK, GOVERNMENT, PUBLIC, SCHOOL, WORKDAY from holidays.groups import InternationalHolidays, ThaiCalendarHolidays -from holidays.holiday_base import HolidayBase - - -class Thailand(HolidayBase, InternationalHolidays, ThaiCalendarHolidays): +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + SAT_TO_NEXT_MON, + SAT_TO_NEXT_TUE, + THU_FRI_TO_NEXT_MON, + SAT_SUN_TO_NEXT_MON, + SAT_SUN_TO_NEXT_TUE, + SAT_SUN_TO_NEXT_MON_TUE, +) + + +class Thailand(ObservedHolidayBase, InternationalHolidays, ThaiCalendarHolidays): """ A subclass of :py:class:`HolidayBase` representing public holidays in Thailand. @@ -33,6 +41,8 @@ class Thailand(HolidayBase, InternationalHolidays, ThaiCalendarHolidays): https://github.com/dr-prodigy/python-holidays/pull/929 - [New Year's Day] (wikisource.org 's wbm) http://tiny.cc/wa_wiki_thai_newyear_2483 + - [National Children's Day] + https://thainews.prd.go.th/banner/th/children'sday/ - [Chakri Memorial Day] (ocac.got.th 's wbm) http://tiny.cc/wa_ocac_chakri - [Songkran Festival] @@ -82,7 +92,24 @@ class Thailand(HolidayBase, InternationalHolidays, ThaiCalendarHolidays): https://en.wikipedia.org/wiki/Royal_Ploughing_Ceremony https://www.lib.ru.ac.th/journal/may/may_phauchmongkol.html https://www.myhora.com/ปฏิทิน/ปฏิทิน-พ.ศ.2540.aspx - + - [Royal Thai Armed Forces Day] + https://th.wikipedia.org/wiki/วันกองทัพไทย + - [Teacher's Day] + https://www.cabinet.soc.go.th/doc_image/2500/718941.pdf + + !!! If Public Holiday falls on weekends, (in lieu) on workday !!! + Despite the wording, this usually only applies to Monday only for + holidays, consecutive holidays all have their own special in lieu + declared separately. + Data from 1992-1994 and 1998-2000 are declared discretely in + special_holidays declarations above. + Applied Automatically for Monday if on Weekends: 1961-1973 + **NOTE: No New Year's Eve (in lieu) for this period + No In Lieu days available: 1974-1988 + Case-by-Case application for Workday if on Weekends: 1989-1994 + Applied Automatically for Workday if on Weekends: 1995-1997 + Case-by-Case application for Workday if on Weekends: 1998-2000 + Applied Automatically for Workday if on Weekends: 2001-Present Limitations: @@ -109,7 +136,11 @@ class Thailand(HolidayBase, InternationalHolidays, ThaiCalendarHolidays): """ country = "TH" + supported_categories = {ARMED_FORCES, BANK, GOVERNMENT, PUBLIC, SCHOOL, WORKDAY} default_language = "th" + # %s (in lieu). + observed_label = tr("ชดเชย%s") + supported_languages = ("en_US", "th") # วันหยุดพิเศษ (เพิ่มเติม) - see Bank of Thailand's DB for Cross-Check. @@ -147,7 +178,7 @@ class Thailand(HolidayBase, InternationalHolidays, ThaiCalendarHolidays): # Songkran Festival (in lieu). songkran_festival_in_lieu_covid = tr("ชดเชยวันสงกรานต์") - special_holidays = { + special_public_holidays = { # 1992-1994 (include In Lieus, Checked with Bank of Thailand Data). 1992: ( (MAY, 18, thai_special_in_lieu_holidays), @@ -253,49 +284,21 @@ class Thailand(HolidayBase, InternationalHolidays, ThaiCalendarHolidays): (JUL, 31, thai_bridge_public_holiday), ), } - supported_languages = ("en_US", "th") - def __init__(self, **kwargs) -> None: + def __init__(self, *args, **kwargs): InternationalHolidays.__init__(self) ThaiCalendarHolidays.__init__(self) - super().__init__(**kwargs) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_MON, *args, **kwargs) - def _populate(self, year): + def _is_observed(self, dt: date) -> bool: + return 1961 <= self._year <= 1973 or 1995 <= self._year <= 1997 or self._year >= 2001 + + def _populate_public_holidays(self): # Due to Thai Calendar Migration, this is capped off at 1941. # But certain holidays were implemented before 1941. - if year <= 1940: + if self._year <= 1940: return None - def _add_observed(dt: date) -> None: - """ - !!! If Public Holiday falls on weekends, (in lieu) on workday !!! - Despite the wording, this usually only applies to Monday only for - holidays, consecutive holidays all have their own special in lieu - declared separately. - - Data from 1992-1994 and 1998-2000 are declared discretely in - special_holidays declarations above. - - Applied Automatically for Monday if on Weekends: 1961-1973 - **NOTE: No New Year's Eve (in lieu) for this period - No In Lieu days available: 1974-1988 - Case-by-Case application for Workday if on Weekends: 1989-1994 - Applied Automatically for Workday if on Weekends: 1995-1997 - Case-by-Case application for Workday if on Weekends: 1998-2000 - Applied Automatically for Workday if on Weekends: 2001-Present - """ - if ( - self.observed - and self._is_weekend(dt) - and (1961 <= year <= 1973 or 1995 <= year <= 1997 or year >= 2001) - ): - in_lieu = dt + td(days=+2 if self._is_saturday(dt) else +1) - for name in self.get_list(dt): - # %s (in lieu) - self._add_holiday(self.tr("ชดเชย%s") % name, in_lieu) - - super()._populate(year) - # Fixed Date Holidays # วันขึ้นปีใหม่ @@ -304,24 +307,22 @@ def _add_observed(dt: date) -> None: # TODO: Add check for 1941 if we support earlier dates. # New Year's Day. - jan_1 = self._add_new_years_day(tr("วันขึ้นปีใหม่")) - _add_observed(jan_1) + self._add_observed(self._add_new_years_day(tr("วันขึ้นปีใหม่"))) - # วันหยุดชดเชยวันสิ้นปี + # วันเด็กแห่งชาติ # Status: In-Use. - # Added separately from New Year's Eve itself so that it would't - # go over the next year. - # - CASE 1: SAT-SUN -> 1 in-lieu on TUE. - # - CASE 2: SUN-MON -> 1 in-lieu on TUE. - # See in lieu logic in `_add_observed(dt: date)`. - - new_years_eve_in_lieu = self.tr("ชดเชย%s") % self.tr("วันสิ้นปี") - - if self.observed and (1995 <= year <= 1997 or year >= 2001): - if self._is_sunday(jan_1): - self._add_new_years_day_three(new_years_eve_in_lieu) - elif self._is_monday(jan_1): - self._add_new_years_day_two(new_years_eve_in_lieu) + # Starts in 1955 as the 1st Monday of October. + # No event was held in 1964 due to date changes came into effect too late. + # Moved to 2nd Saturday of January since 1965. + # No in-lieus are observed, and still remain a Public Holidays than just Observed. + + if self._year >= 1955 and self._year != 1964: + # National Children's Day + childrens_day = tr("วันเด็กแห่งชาติ") + if self._year <= 1963: + self._add_holiday_1st_mon_of_oct(childrens_day) + else: + self._add_holiday_2nd_sat_of_jan(childrens_day) # วันจักรี # Status: In-Use. @@ -329,7 +330,7 @@ def _add_observed(dt: date) -> None: # TODO: Add check for 1918 if we support earlier dates. # Chakri Memorial Day. - _add_observed(self._add_holiday_apr_6(tr("วันจักรี"))) + self._add_observed(self._add_holiday_apr_6(tr("วันจักรี"))) # วันสงกรานต์ # Status: In-Use. @@ -344,20 +345,19 @@ def _add_observed(dt: date) -> None: # (Except for 2020 due to Covid-19 outbreaks) # This has its own in-lieu trigger. - if year >= 1948: + if 1948 <= self._year <= 1953 or 1957 <= self._year != 2020: # Songkran Festival. songkran_festival = tr("วันสงกรานต์") - if year <= 1953 or (1957 <= year != 2020): - dt = ( - self._add_holiday_apr_12(songkran_festival) - if 1989 <= year <= 1997 - else self._add_holiday_apr_13(songkran_festival) - ) - if 1957 <= year <= 1988: - _add_observed(dt) - else: - self._add_holiday(songkran_festival, dt + td(days=+1)) - self._add_holiday(songkran_festival, dt + td(days=+2)) + if 1957 <= self._year <= 1988: + self._add_observed(self._add_holiday_apr_13(songkran_festival)) + elif 1989 <= self._year <= 1997: + dt = self._add_holiday_apr_12(songkran_festival) + self._add_holiday_apr_13(songkran_festival) + self._add_holiday_apr_14(songkran_festival) + else: + dt = self._add_holiday_apr_13(songkran_festival) + self._add_holiday_apr_14(songkran_festival) + self._add_holiday_apr_15(songkran_festival) # วันหยุดชดเชยวันสงกรานต์ # If Songkran happened to be held on the weekends, only one in-lieu @@ -368,13 +368,8 @@ def _add_observed(dt: date) -> None: # See in lieu logic in `_add_observed(dt: date)`. # Status: In Use. - songkran_festival_in_lieu = self.tr("ชดเชย%s") % songkran_festival - - if self.observed and (1995 <= year <= 1997 or 2001 <= year != 2020): - if self._is_thursday(dt): - self._add_holiday(songkran_festival_in_lieu, dt + td(days=+4)) - elif self._is_friday(dt) or self._is_saturday(dt): - self._add_holiday(songkran_festival_in_lieu, dt + td(days=+3)) + if self._year >= 1995: + self._add_observed(dt, rule=THU_FRI_TO_NEXT_MON + SAT_TO_NEXT_TUE) # วันแรงงานแห่งชาติ # Status: In-Use. @@ -382,9 +377,9 @@ def _add_observed(dt: date) -> None: # Does existed officially since 1956 (B.E. 2499), but wasn't a public holiday until then. # *** NOTE: only observed by financial and private sectors. - if year >= 1974: + if self._year >= 1974: # National Labour day. - _add_observed(self._add_labor_day(tr("วันแรงงานแห่งชาติ"))) + self._add_observed(self._add_labor_day(tr("วันแรงงานแห่งชาติ"))) # วันชาติ # Status: In-Use. @@ -393,9 +388,11 @@ def _add_observed(dt: date) -> None: # TODO: Add check for 1939 if we support earlier dates. # National Day. - name = tr("วันชาติ") - _add_observed( - self._add_holiday_jun_24(name) if year <= 1959 else self._add_holiday_dec_5(name) + national_day = tr("วันชาติ") + self._add_observed( + self._add_holiday_jun_24(national_day) + if self._year <= 1959 + else self._add_holiday_dec_5(national_day) ) # วันฉัตรมงคล @@ -406,19 +403,19 @@ def _add_observed(dt: date) -> None: # Coronation Day. coronation_day = tr("วันฉัตรมงคล") - if 1958 <= year <= 2016: - _add_observed(self._add_holiday_may_5(coronation_day)) - elif year >= 2020: - _add_observed(self._add_holiday_may_4(coronation_day)) + if 1958 <= self._year <= 2016: + self._add_observed(self._add_holiday_may_5(coronation_day)) + elif self._year >= 2020: + self._add_observed(self._add_holiday_may_4(coronation_day)) # วันเฉลิมพระชนมพรรษา พระราชินี # Status: In-Use. # Starts in 2019 (B.E. 2562). - if year >= 2019: - _add_observed( - # HM Queen Suthida's Birthday. + if self._year >= 2019: + self._add_observed( self._add_holiday_jun_3( + # HM Queen Suthida's Birthday. tr("วันเฉลิมพระชนมพรรษาสมเด็จพระนางเจ้าสุทิดา พัชรสุธาพิมลลักษณ พระบรมราชินี") ) ) @@ -427,8 +424,8 @@ def _add_observed(dt: date) -> None: # Status: In-Use. # Started in 2017 (B.E 2560). - if year >= 2017: - _add_observed( + if self._year >= 2017: + self._add_observed( self._add_holiday_jul_28( # HM King Maha Vajiralongkorn's Birthday. tr( @@ -445,15 +442,15 @@ def _add_observed(dt: date) -> None: # Initial celebration as HM Queen Sirikit's Birthday. # Now acts as the Queen Mother from 2017 onwards. - if year >= 1976: - name = ( + if self._year >= 1976: + q_sirikit_bday = ( # HM Queen Sirikit the Queen Mother's Birthday. tr("วันเฉลิมพระชนมพรรษาสมเด็จพระบรมราชชนนีพันปีหลวง") - if year >= 2017 + if self._year >= 2017 # HM Queen Sirikit's Birthday. else tr("วันเฉลิมพระชนมพรรษาสมเด็จพระนางเจ้าสิริกิติ์ พระบรมราชินีนาถ") ) - _add_observed(self._add_holiday_aug_12(name)) + self._add_observed(self._add_holiday_aug_12(q_sirikit_bday)) # วันแม่แห่งชาติ # Status: In-Use. @@ -465,28 +462,28 @@ def _add_observed(dt: date) -> None: # National Mother's Day. thai_mothers_day = tr("วันแม่แห่งชาติ") - if 1950 <= year <= 1957: - _add_observed(self._add_holiday_apr_15(thai_mothers_day)) - elif year >= 1976: - _add_observed(self._add_holiday_aug_12(thai_mothers_day)) + if 1950 <= self._year <= 1957: + self._add_observed(self._add_holiday_apr_15(thai_mothers_day)) + elif self._year >= 1976: + self._add_observed(self._add_holiday_aug_12(thai_mothers_day)) # วันคล้ายวันสวรรคตพระบาทสมเด็จพระปรมินทร มหาภูมิพลอดุลยเดช บรมนาถบพิตร # Status: In-Use. # Started in 2017 (B.E 2560). # Got conferred with 'the Great' title in 2019 (B.E. 2562). - if year >= 2017: - name = ( + if self._year >= 2017: + k_bhumibol_memorial = ( # Anniversary for the Death of King Bhumibol Adulyadej the Great. tr( "วันคล้ายวันสวรรคตพระบาทสมเด็จพระบรมชนกาธิเบศร " "มหาภูมิพลอดุลยเดชมหาราช บรมนาถบพิตร" ) - if year >= 2019 + if self._year >= 2019 # Anniversary for the Death of King Bhumibol Adulyadej. else tr("วันคล้ายวันสวรรคตพระบาทสมเด็จพระปรมินทรมหาภูมิพลอดุลยเดช บรมนาถบพิตร") ) - _add_observed(self._add_holiday_oct_13(name)) + self._add_observed(self._add_holiday_oct_13(k_bhumibol_memorial)) # วันปิยมหาราช # Status: In-Use. @@ -494,7 +491,7 @@ def _add_observed(dt: date) -> None: # TODO: Add check for 1911 if we support earlier dates. # HM King Chulalongkorn Memorial Day. - _add_observed(self._add_holiday_oct_23(tr("วันปิยมหาราช"))) + self._add_observed(self._add_holiday_oct_23(tr("วันปิยมหาราช"))) # วันเฉลิมพระชนมพรรษา รัชกาลที่ 9 (1960-2016) # วันคล้ายวันเฉลิมพระชนมพรรษา รัชกาลที่ 9 (2017-Present) @@ -503,28 +500,28 @@ def _add_observed(dt: date) -> None: # Confirmed as still in-use in 2017. # Got conferred with 'the Great' title in 2019 (B.E. 2562). - if year >= 1960: - name = ( + if self._year >= 1960: + k_bhumibol_bday = ( # HM King Bhumibol Adulyadej's the Great's Birthday Anniversary. tr( "วันคล้ายวันเฉลิมพระชนมพรรษาพระบาทสมเด็จพระบรม" "ชนกาธิเบศร มหาภูมิพลอดุลยเดชมหาราช บรมนาถบพิตร" ) - if year >= 2019 + if self._year >= 2019 else ( # HM King Bhumibol Adulyadej Birthday Anniversary. tr( "วันคล้ายวันเฉลิมพระชนมพรรษา" "พระบาทสมเด็จพระปรมินทรมหาภูมิพลอดุลยเดช บรมนาถบพิตร" ) - if year >= 2016 + if self._year >= 2016 # HM King Bhumibol Adulyadej Birthday Anniversary. else tr( "วันเฉลิมพระชนมพรรษาพระบาทสมเด็จพระปรมินทรมหาภูมิพลอดุลยเดช บรมนาถบพิตร" ) ) ) - _add_observed(self._add_holiday_dec_5(name)) + self._add_observed(self._add_holiday_dec_5(k_bhumibol_bday)) # วันพ่อแห่งชาติ # Status: In-Use. @@ -532,9 +529,9 @@ def _add_observed(dt: date) -> None: # Technically, a replication of HM King Bhumibol Adulyadej's Birthday # but it's in the official calendar, so may as well have this here. - if year >= 1980: + if self._year >= 1980: # National Father's Day. - _add_observed(self._add_holiday_dec_5(tr("วันพ่อแห่งชาติ"))) + self._add_observed(self._add_holiday_dec_5(tr("วันพ่อแห่งชาติ"))) # วันรัฐธรรมนูญ # Status: In-Use. @@ -543,7 +540,7 @@ def _add_observed(dt: date) -> None: # TODO: Add check for 1932 if we support earlier dates. # Constitution Day. - _add_observed(self._add_holiday_dec_10(tr("วันรัฐธรรมนูญ"))) + self._add_observed(self._add_holiday_dec_10(tr("วันรัฐธรรมนูญ"))) # วันสิ้นปี # Status: In-Use. @@ -553,7 +550,19 @@ def _add_observed(dt: date) -> None: # This has its own in-lieu trigger. # New Year's Eve. - self._add_new_years_eve(tr("วันสิ้นปี")) + name = tr("วันสิ้นปี") + self._add_new_years_eve(name) + + # วันหยุดชดเชยวันสิ้นปี + # Status: In-Use. + # Added separately from New Year's Eve itself so that it would't + # go over the next year. + # - CASE 1: SAT-SUN -> 1 in-lieu on TUE. + # - CASE 2: SUN-MON -> 1 in-lieu on TUE. + # See in lieu logic in `_add_observed(dt: date)`. + + if self._year >= 1995: + self._add_observed(date(self._year - 1, DEC, 31), name=name, rule=SAT_SUN_TO_NEXT_TUE) # Thai Lunar Calendar Holidays # See `_ThaiLunisolar` in holidays/utils.py for more details. @@ -565,7 +574,7 @@ def _add_observed(dt: date) -> None: # Makha Bucha. makha_bucha_date = self._add_makha_bucha(tr("วันมาฆบูชา")) if makha_bucha_date: - _add_observed(makha_bucha_date) + self._add_observed(makha_bucha_date) # วันวิสาขบูชา # Status: In-Use. @@ -573,58 +582,93 @@ def _add_observed(dt: date) -> None: # Visakha Bucha. visakha_bucha_date = self._add_visakha_bucha(tr("วันวิสาขบูชา")) if visakha_bucha_date: - _add_observed(visakha_bucha_date) + self._add_observed(visakha_bucha_date) # วันอาสาฬหบูชา # Status: In-Use. - # This has its own in-lieu trigger. + # - CASE 1: FRI-SAT -> 1 in-lieu on MON + # - CASE 2: SAT-SUN -> 1 in-lieu on MON + # - CASE 3: SUN-MON -> 1 in-lieu on TUE # Asarnha Bucha. asarnha_bucha_date = self._add_asarnha_bucha(tr("วันอาสาฬหบูชา")) + if asarnha_bucha_date: + self._add_observed(asarnha_bucha_date, rule=SAT_SUN_TO_NEXT_MON_TUE) # วันเข้าพรรษา # Status: In-Use. - # This has its own in-lieu trigger. - - # Buddhist Lent Day. - self._add_khao_phansa(tr("วันเข้าพรรษา")) - - # วันหยุดชดเชยวันอาสาฬหบูชา - # วันหยุดชดเชยวันเข้าพรรษา - # Status: In Use. # - CASE 1: FRI-SAT -> 1 in-lieu on MON # - CASE 2: SAT-SUN -> 1 in-lieu on MON # - CASE 3: SUN-MON -> 1 in-lieu on TUE - # See in lieu logic in `_add_observed(dt: date)`. - if ( - asarnha_bucha_date - and self.observed - and (1961 <= year <= 1973 or 1995 <= year <= 1997 or year >= 2001) - ): - if self._is_friday(asarnha_bucha_date): - self._add_holiday( - self.tr("ชดเชย%s") % self.tr("วันเข้าพรรษา"), asarnha_bucha_date + td(days=+3) - ) - elif self._is_weekend(asarnha_bucha_date): - self._add_holiday( - self.tr("ชดเชย%s") % self.tr("วันอาสาฬหบูชา"), asarnha_bucha_date + td(days=+2) - ) + # Buddhist Lent Day. + khao_phansa_date = self._add_khao_phansa(tr("วันเข้าพรรษา")) + if khao_phansa_date: + self._add_observed(khao_phansa_date, rule=SAT_TO_NEXT_MON) + + def _populate_armed_forces_holidays(self): + # วันกองทัพไทย + # Status: In-Use. + # First started in 1959 on the foundation of Ministry of Defense Day (APR 8). + # Moved to JAN 25 (Supposedly King Naresuan's Decisive Battle) in 1980. + # Corrected to the battle's actual date (JAN 18) in 2007. + # Only applys to members of the Royal Thai Armed Forces. + + if self._year >= 1959: + # Royal Thai Armed Forces Day + armed_forces_day = tr("วันกองทัพไทย") + if self._year >= 2007: + self._add_holiday_jan_18(armed_forces_day) + elif self._year >= 1980: + self._add_holiday_jan_25(armed_forces_day) + else: + self._add_holiday_apr_8(armed_forces_day) + + def _populate_bank_holidays(self): + # Bank of Thailand, the ones who decreed this wasn't found until December 10, 1942 + # So it's safe to assume with that as our start date. + if self._year <= 1942: + return None + + # Bank Holidays + + # วันหยุดเพิ่มเติมสำหรับการปิดบัญชีประจำปีของธนาคารเพื่อการเกษตรและสหกรณ์การเกษตร + # Status: Defunct. + # If held on the weekends, no in-lieus. + # Abandoned in 2022. + + if self._year <= 2021: + self._add_holiday_apr_1( + # Additional Closing Day for Bank for Agriculture and Agricultural Cooperatives + tr( + "วันหยุดเพิ่มเติมสำหรับการปิดบัญชีประจำปีของ" + "ธนาคารเพื่อการเกษตรและสหกรณ์การเกษตร" + ), + ) + + # วันหยุดภาคครึ่งปีของสถาบันการเงินและสถาบันการเงินเฉพาะกิจ + # Status: Defunct. + # If held on the weekends, no in-lieus. + # Abandoned in 2019. + if self._year <= 2018: + self._add_holiday_jul_1( + # Mid-Year Closing Day + tr("วันหยุดภาคครึ่งปีของสถาบันการเงินและสถาบันการเงินเฉพาะกิจ"), + ) + + def _populate_government_holidays(self): # No Future Fixed Date Holidays # วันพืชมงคล # Restarts in 1957 (B.E. 2500). - # Is dated on an annual basis by the Royal Palace. + # Is dated on an annual basis by the Royal Palace, always on weekdays. # This isn't even fixed even by the Thai Lunar Calendar, but instead # by Court Astrologers; All chosen dates are all around May, so we # can technically assign it to 13 May for years prior with no data. # *** NOTE: only observed by government sectors. # TODO: Update this annually around Dec of each year. - # Royal Ploughing Ceremony. - raeknakhwan = tr("วันพืชมงคล") - raeknakhwan_dates = { 1997: (MAY, 13), 1998: (MAY, 13), @@ -654,12 +698,94 @@ def _add_observed(dt: date) -> None: 2022: (MAY, 17), 2023: (MAY, 11), } - # For years with exact date data. - if year in raeknakhwan_dates: - _add_observed(self._add_holiday(raeknakhwan, raeknakhwan_dates[year])) - # Approx. otherwise for 1957-2013. - elif 1957 <= year <= 1996: - _add_observed(self._add_holiday_may_13(raeknakhwan)) + if 1957 <= self._year <= 2023 and self._year != 1999: + self._add_observed( + # Royal Ploughing Ceremony. + self._add_holiday(tr("วันพืชมงคล"), raeknakhwan_dates.get(self._year, (MAY, 13))) + ) + + def _populate_school_holidays(self): + # วันครู + # Status: In-Use. + # Started in 1957. + # Only applies to Ministry of Education (Students, Teachers, etc.), no in-lieus are given. + + if self._year >= 1957: + # Teacher's Day + self._add_holiday_jan_16(tr("วันครู")) + + def _populate_workday_holidays(self): + # These are classes as "วันสำคัญ" (Date of National Observance) by the government + # but are not holidays. + + if self._year >= 1948: + # วันทหารผ่านศึก + # Status: In-Use. + # Started in 1948. + + # Thai Veterans Day + self._add_holiday_feb_3(tr("วันทหารผ่านศึก")) + + if self._year >= 1982: + # วันวิทยาศาสตร์แห่งชาติ + # Status: In-Use. + # Started in 1982. + + # National Science Day + self._add_holiday_aug_18(tr("วันวิทยาศาสตร์แห่งชาติ")) + + if self._year >= 1985: + # วันศิลปินแห่งชาติ + # Status: In-Use. + # Started in 1985. + + # National Artist Day + self._add_holiday_feb_26(tr("วันศิลปินแห่งชาติ")) + + if self._year >= 1989: + # วันสตรีสากล + # Status: In-Use. + # Started in 1989. + + # International Women's Day + self._add_womens_day(tr("วันสตรีสากล")) + + if self._year >= 1990: + # วันอนุรักษ์ทรัพยากรป่าไม้ของชาติ + # Status: In-Use. + # Started in 1990. + + # National Forest Conservation Day + self._add_holiday_jan_14(tr("วันอนุรักษ์ทรัพยากรป่าไม้ของชาติ")) + + # วันพ่อขุนรามคำแหงมหาราช + # Status: In-Use. + # Started in 1990. + + # HM King Ramkamhaeng Memorial Day + self._add_holiday_jan_17(tr("วันพ่อขุนรามคำแหงมหาราช")) + + if self._year >= 1995: + # วันการบินแห่งชาติ + # Status: In-Use. + # Started in 1995. + + # National Aviation Day + self._add_holiday_jan_13(tr("วันการบินแห่งชาติ")) + + if self._year >= 2017: + # วันพระราชทานธงชาติไทย + # Status: In-Use. + # Started in 2017. + + # Thai National Flag Day + self._add_holiday_sep_28(tr("วันพระราชทานธงชาติไทย")) + + # วันลอยกระทง + # Status: In-Use. + + # Loy Krathong + self._add_loy_krathong(tr("วันลอยกระทง")) class TH(Thailand): diff --git a/holidays/countries/ukraine.py b/holidays/countries/ukraine.py index 6bebc1d6a..df52b64d6 100644 --- a/holidays/countries/ukraine.py +++ b/holidays/countries/ukraine.py @@ -10,7 +10,6 @@ # License: MIT (see LICENSE file) from datetime import date -from datetime import timedelta as td from gettext import gettext as tr from holidays.calendars.gregorian import ( @@ -29,10 +28,10 @@ ) from holidays.calendars.julian import JULIAN_CALENDAR from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SAT_SUN_TO_NEXT_WORKDAY -class Ukraine(HolidayBase, ChristianHolidays, InternationalHolidays): +class Ukraine(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ Current holidays list: https://zakon1.rada.gov.ua/laws/show/322-08/paran454#n454 @@ -68,6 +67,8 @@ class Ukraine(HolidayBase, ChristianHolidays, InternationalHolidays): country = "UA" default_language = "uk" + # %s (Observed). + observed_label = tr("%s (вихідний)") supported_languages = ("ar", "en_US", "uk") # Date format (see strftime() Format Codes) substituted_date_format = tr("%d.%m.%Y") @@ -192,7 +193,16 @@ class Ukraine(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self, JULIAN_CALENDAR) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_WORKDAY, *args, **kwargs) + + def _is_observed(self, dt: date) -> bool: + # 27.01.1995: holiday on weekend move to next workday + # https://zakon.rada.gov.ua/laws/show/35/95-вр + # 10.01.1998: cancelled + # https://zakon.rada.gov.ua/laws/show/785/97-вр + # 23.04.1999: holiday on weekend move to next workday + # https://zakon.rada.gov.ua/laws/show/576-14 + return date(1995, JAN, 27) <= dt <= date(1998, JAN, 9) or dt >= date(1999, APR, 23) def _populate(self, year): # The current set of holidays came into force in 1991 @@ -284,23 +294,8 @@ def _populate(self, year): ) ) - # 27.01.1995: holiday on weekend move to next workday - # https://zakon.rada.gov.ua/laws/show/35/95-вр - # 10.01.1998: cancelled - # https://zakon.rada.gov.ua/laws/show/785/97-вр - # 23.04.1999: holiday on weekend move to next workday - # https://zakon.rada.gov.ua/laws/show/576-14 - if not self.observed: - return None - for dt in sorted(dts_observed): - if self._is_weekend(dt) and ( - date(1995, JAN, 27) <= dt <= date(1998, JAN, 9) or dt >= date(1999, APR, 23) - ): - dt_observed = dt + td(days=+2 if self._is_saturday(dt) else +1) - while dt_observed in self: - dt_observed += td(days=+1) - for name in self.get_list(dt): - self._add_holiday(self.tr("%s (вихідний)") % name, dt_observed) + if self.observed: + self._populate_observed(dts_observed) class UA(Ukraine): diff --git a/holidays/countries/united_kingdom.py b/holidays/countries/united_kingdom.py index bac8649a7..21c87cc80 100644 --- a/holidays/countries/united_kingdom.py +++ b/holidays/countries/united_kingdom.py @@ -9,21 +9,28 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td from typing import Tuple, Union from holidays.calendars.gregorian import APR, MAY, JUN, JUL, SEP, DEC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + MON_TO_NEXT_TUE, + SAT_SUN_TO_NEXT_MON, + SAT_SUN_TO_NEXT_MON_TUE, +) -class UnitedKingdom(HolidayBase, ChristianHolidays, InternationalHolidays): +class UnitedKingdom(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ - https://en.wikipedia.org/wiki/Public_holidays_in_the_United_Kingdom + References: + - https://en.wikipedia.org/wiki/Public_holidays_in_the_United_Kingdom + - https://www.gov.uk/bank-holidays + - https://www.timeanddate.com/holidays/uk/ """ country = "GB" + observed_label = "%s (Observed)" special_holidays = { 1977: (JUN, 7, "Silver Jubilee of Elizabeth II"), 1981: (JUL, 29, "Wedding of Charles and Diana"), @@ -54,13 +61,7 @@ class UnitedKingdom(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, days: int = +1) -> None: - if self.observed and self._is_weekend(dt): - self._add_holiday( - "%s (Observed)" % self[dt], dt + td(days=+2 if self._is_saturday(dt) else days) - ) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year: int) -> None: super()._populate(year) @@ -105,10 +106,14 @@ def _add_subdiv_holidays(self): self._add_observed(self._add_new_years_day("New Year's Day")) # Christmas Day - self._add_observed(self._add_christmas_day("Christmas Day"), days=+2) + self._add_observed( + self._add_christmas_day("Christmas Day"), rule=SAT_SUN_TO_NEXT_MON_TUE + ) # Boxing Day - self._add_observed(self._add_christmas_day_two("Boxing Day"), days=+2) + self._add_observed( + self._add_christmas_day_two("Boxing Day"), rule=SAT_SUN_TO_NEXT_MON_TUE + ) super()._add_subdiv_holidays() @@ -129,7 +134,7 @@ def _add_subdiv_nir_holidays(self): self._add_easter_monday("Easter Monday") # Battle of the Boyne - self._add_holiday_jul_12("Battle of the Boyne") + self._add_observed(self._add_holiday_jul_12("Battle of the Boyne")) # Late Summer bank holiday (last Monday in August) if self._year >= 1971: @@ -137,35 +142,32 @@ def _add_subdiv_nir_holidays(self): def _add_subdiv_sct_holidays(self): # New Year's Day - name = "New Year's Day" - jan_1 = self._add_new_years_day(name) - if self.observed and self._is_weekend(jan_1): - self._add_holiday( - "%s (Observed)" % name, jan_1 + td(days=+3 if self._is_saturday(jan_1) else +1) - ) + self._add_observed(self._add_new_years_day("New Year's Day")) # New Year Holiday - name = "New Year Holiday" - jan_2 = self._add_new_years_day_two(name) - self._add_observed(jan_2) - if self.observed and self._is_monday(jan_2): - self._add_new_years_day_three("%s (Observed)" % name) + self._add_observed( + self._add_new_years_day_two("New Year Holiday"), + rule=SAT_SUN_TO_NEXT_MON_TUE + MON_TO_NEXT_TUE, + ) # Summer bank holiday (first Monday in August) self._add_holiday_1st_mon_of_aug("Summer Bank Holiday") if self._year >= 2006: # St. Andrew's Day - self._add_holiday_nov_30("St. Andrew's Day") + self._add_observed(self._add_holiday_nov_30("St. Andrew's Day")) # Christmas Day self._add_observed( - self._add_christmas_day("Christmas Day"), days=+2 if self._year >= 1974 else +1 + self._add_christmas_day("Christmas Day"), + rule=SAT_SUN_TO_NEXT_MON_TUE if self._year >= 1974 else SAT_SUN_TO_NEXT_MON, ) if self._year >= 1974: # Boxing Day - self._add_observed(self._add_christmas_day_two("Boxing Day"), days=+2) + self._add_observed( + self._add_christmas_day_two("Boxing Day"), rule=SAT_SUN_TO_NEXT_MON_TUE + ) def _add_subdiv_wls_holidays(self): # Easter Monday diff --git a/holidays/countries/united_states.py b/holidays/countries/united_states.py index f1f0f13c6..6cfa821de 100644 --- a/holidays/countries/united_states.py +++ b/holidays/countries/united_states.py @@ -9,16 +9,22 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td from typing import Tuple, Union -from holidays.calendars.gregorian import DEC, FRI, _get_nth_weekday_from +from holidays.calendars.gregorian import DEC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase - - -class UnitedStates(HolidayBase, ChristianHolidays, InternationalHolidays): +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + MON_TO_NEXT_TUE, + FRI_TO_PREV_THU, + SAT_TO_PREV_FRI, + SUN_TO_NEXT_MON, + SAT_SUN_TO_PREV_FRI, + SAT_SUN_TO_NEXT_MON, +) + + +class UnitedStates(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://en.wikipedia.org/wiki/Public_holidays_in_the_United_States @@ -28,6 +34,7 @@ class UnitedStates(HolidayBase, ChristianHolidays, InternationalHolidays): """ country = "US" + observed_label = "%s (Observed)" subdivisions: Union[Tuple[()], Tuple[str, ...]] = ( "AK", "AL", @@ -94,15 +101,7 @@ class UnitedStates(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, before: bool = True, after: bool = True) -> None: - if not self.observed: - return None - if self._is_saturday(dt) and before: - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=-1)) - elif self._is_sunday(dt) and after: - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=+1)) + super().__init__(observed_rule=SAT_TO_PREV_FRI + SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): super()._populate(year) @@ -110,11 +109,11 @@ def _populate(self, year): # New Year's Day if year >= 1871: name = "New Year's Day" - self._add_observed(self._add_new_years_day(name), before=False) + self._add_observed(self._add_new_years_day(name)) # The following year's observed New Year's Day can be in this year # when it falls on a Friday (Jan 1st is a Saturday). if self.observed and self._is_friday(DEC, 31): - self._add_holiday_dec_31("%s (Observed)" % name) + self._add_holiday_dec_31(self.observed_label % name) # Memorial Day if year >= 1888: @@ -154,15 +153,12 @@ def _populate(self, year): def _add_christmas_eve_holiday(self): # Christmas Eve - name = "Christmas Eve" - dec_24 = self._add_christmas_eve(name) - if self.observed: - # If on Friday, observed on Thursday - if self._is_friday(dec_24): - self._add_holiday("%s (Observed)" % name, dec_24 + td(days=-1)) - # If on Saturday or Sunday, observed on Friday - elif self._is_weekend(dec_24): - self._add_holiday("%s (Observed)" % name, _get_nth_weekday_from(-1, FRI, dec_24)) + # If on Friday, observed on Thursday + # If on Saturday or Sunday, observed on Friday + self._add_observed( + self._add_christmas_eve("Christmas Eve"), + rule=FRI_TO_PREV_THU + SAT_SUN_TO_PREV_FRI, + ) def _add_subdiv_holidays(self): # Martin Luther King Jr. Day @@ -275,7 +271,7 @@ def _add_subdiv_ca_holidays(self): # Cesar Chavez Day if self._year >= 1995: - self._add_observed(self._add_holiday_mar_31("Cesar Chavez Day"), before=False) + self._add_observed(self._add_holiday_mar_31("Cesar Chavez Day"), rule=SUN_TO_NEXT_MON) # Day After Thanksgiving if self._year >= 1975: @@ -300,7 +296,7 @@ def _add_subdiv_dc_holidays(self): self._add_holiday_jan_20(name) if self._year >= 1937 else self._add_holiday_mar_4(name), - before=False, + rule=SUN_TO_NEXT_MON, ) # Emancipation Day @@ -450,7 +446,7 @@ def _add_subdiv_ky_holidays(self): # New Year's Eve if self._year >= 2013: - self._add_observed(self._add_new_years_eve("New Year's Eve"), after=False) + self._add_observed(self._add_new_years_eve("New Year's Eve")) def _add_subdiv_la_holidays(self): # Inauguration Day @@ -460,7 +456,7 @@ def _add_subdiv_la_holidays(self): self._add_holiday_jan_20(name) if self._year >= 1937 else self._add_holiday_mar_4(name), - before=False, + rule=SUN_TO_NEXT_MON, ) # Mardi Gras @@ -477,10 +473,9 @@ def _add_subdiv_la_holidays(self): def _add_subdiv_ma_holidays(self): # Evacuation Day if self._year >= 1901: - name = "Evacuation Day" - mar_17 = self._add_holiday_mar_17(name) - if self.observed and self._is_weekend(mar_17): - self._add_holiday_1st_mon_from_mar_17("%s (Observed)" % name) + self._add_observed( + self._add_holiday_mar_17("Evacuation Day"), rule=SAT_SUN_TO_NEXT_MON + ) # Patriots' Day if self._year >= 1894: @@ -498,7 +493,7 @@ def _add_subdiv_md_holidays(self): self._add_holiday_jan_20(name) if self._year >= 1937 else self._add_holiday_mar_4(name), - before=False, + rule=SUN_TO_NEXT_MON, ) # American Indian Heritage Day @@ -523,7 +518,7 @@ def _add_subdiv_mi_holidays(self): self._add_christmas_eve_holiday() # New Year's Eve - self._add_observed(self._add_new_years_eve("New Year's Eve"), after=False) + self._add_observed(self._add_new_years_eve("New Year's Eve")) def _add_subdiv_mn_holidays(self): pass @@ -583,15 +578,12 @@ def _add_subdiv_nc_holidays(self): # Day After Christmas if self._year >= 2013: - name = "Day After Christmas" - dec_26 = self._add_christmas_day_two(name) - if self.observed: - # If on Saturday or Sunday, observed on Monday - if self._is_weekend(dec_26): - self._add_holiday_1st_mon_from_dec_26("%s (Observed)" % name) - # If on Monday, observed on Tuesday - elif self._is_monday(dec_26): - self._add_holiday("%s (Observed)" % name, dec_26 + td(days=+1)) + # If on Saturday or Sunday, observed on Monday + # If on Monday, observed on Tuesday + self._add_observed( + self._add_christmas_day_two("Day After Christmas"), + rule=MON_TO_NEXT_TUE + SAT_SUN_TO_NEXT_MON, + ) def _add_subdiv_nd_holidays(self): pass @@ -683,16 +675,16 @@ def _add_subdiv_pr_holidays(self): self._add_holiday_3rd_mon_of_feb("Presidents' Day") # Emancipation Day - self._add_observed(self._add_holiday_mar_22("Emancipation Day"), before=False) + self._add_observed(self._add_holiday_mar_22("Emancipation Day"), rule=SUN_TO_NEXT_MON) # Good Friday self._add_good_friday("Good Friday") # Constitution Day - self._add_observed(self._add_holiday_jul_25("Constitution Day"), before=False) + self._add_observed(self._add_holiday_jul_25("Constitution Day"), rule=SUN_TO_NEXT_MON) # Discovery Day - self._add_observed(self._add_holiday_nov_19("Discovery Day"), before=False) + self._add_observed(self._add_holiday_nov_19("Discovery Day"), rule=SUN_TO_NEXT_MON) def _add_subdiv_pw_holidays(self): pass @@ -786,7 +778,7 @@ def _add_subdiv_va_holidays(self): self._add_holiday_jan_20(name) if self._year >= 1937 else self._add_holiday_mar_4(name), - before=False, + rule=SUN_TO_NEXT_MON, ) def _add_subdiv_vi_holidays(self): @@ -851,7 +843,7 @@ def _add_subdiv_wi_holidays(self): self._add_christmas_eve_holiday() # New Year's Eve - self._add_observed(self._add_new_years_eve("New Year's Eve"), after=False) + self._add_observed(self._add_new_years_eve("New Year's Eve")) def _add_subdiv_wv_holidays(self): # West Virginia Day diff --git a/holidays/countries/uruguay.py b/holidays/countries/uruguay.py index 18b2f6ed0..22e84e5a1 100644 --- a/holidays/countries/uruguay.py +++ b/holidays/countries/uruguay.py @@ -13,13 +13,17 @@ from datetime import timedelta as td from gettext import gettext as tr -from holidays.calendars.gregorian import MAR, JUN, DEC, MON, _get_nth_weekday_from +from holidays.calendars.gregorian import MAR from holidays.constants import BANK, PUBLIC from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ( + ObservedHolidayBase, + TUE_WED_TO_PREV_MON, + THU_FRI_TO_NEXT_MON, +) -class Uruguay(HolidayBase, ChristianHolidays, InternationalHolidays): +class Uruguay(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ References: - https://en.wikipedia.org/wiki/Public_holidays_in_Uruguay @@ -49,22 +53,14 @@ class Uruguay(HolidayBase, ChristianHolidays, InternationalHolidays): 2020: (MAR, 1, presidential_inauguration_day), } - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _move_holiday(self, dt: date) -> None: # Decree Law #14977, # 15535, #16805. - if self.observed and (1980 <= self._year <= 1983 or self._year >= 1997): - dt_observed = None - if self._is_tuesday(dt) or self._is_wednesday(dt): - dt_observed = _get_nth_weekday_from(-1, MON, dt) - elif self._is_thursday(dt) or self._is_friday(dt): - dt_observed = _get_nth_weekday_from(1, MON, dt) - if dt_observed: - self._add_holiday(self[dt], dt_observed) - self.pop(dt) + super().__init__(observed_rule=TUE_WED_TO_PREV_MON + THU_FRI_TO_NEXT_MON, *args, **kwargs) + + def _is_observed(self, dt: date) -> bool: + return 1980 <= self._year <= 1983 or self._year >= 1997 def _populate_public_holidays(self): # Law # 6997. @@ -111,7 +107,7 @@ def _populate_public_holidays(self): if self._year <= 1932 or 1936 <= self._year <= 1979: # Beaches Day. - self._add_holiday(tr("Día de las Playas"), DEC, 8) + self._add_holiday_dec_8(tr("Día de las Playas")) # Day of the Family. self._add_christmas_day(tr("Día de la Familia")) @@ -149,7 +145,7 @@ def _populate_bank_holidays(self): if self._year <= 1932 or self._year >= 1940: # Birthday of Artigas. - dt = self._add_holiday(tr("Natalicio de Artigas"), JUN, 19) + dt = self._add_holiday_jun_19(tr("Natalicio de Artigas")) if self._year <= 2001: self._move_holiday(dt) diff --git a/holidays/countries/vanuatu.py b/holidays/countries/vanuatu.py index ef0ce5f08..4df9f68af 100644 --- a/holidays/countries/vanuatu.py +++ b/holidays/countries/vanuatu.py @@ -9,15 +9,12 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.calendars.gregorian import JUL, OCT from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON, MON_TO_NEXT_TUE -class Vanuatu(HolidayBase, ChristianHolidays, InternationalHolidays): +class Vanuatu(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://en.wikipedia.org/wiki/Public_holidays_in_Vanuatu https://www.timeanddate.com/holidays/vanuatu/ @@ -41,11 +38,7 @@ class Vanuatu(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date) -> None: - if self.observed and self._is_sunday(dt): - self._add_holiday(self.observed_label % self[dt], dt + td(days=+1)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): # On 30 July 1980, Vanuatu gained independence from Britain and France. @@ -95,10 +88,9 @@ def _populate(self, year): self._add_christmas_day("Christmas Day") # Family Day. - name = "Family Day" - dec_26 = self._add_christmas_day_two(name) - if self.observed and self._is_monday(dec_26): - self._add_holiday(self.observed_label % name, dec_26 + td(days=+1)) + self._add_observed( + self._add_christmas_day_two("Family Day"), rule=SUN_TO_NEXT_MON + MON_TO_NEXT_TUE + ) class VU(Vanuatu): diff --git a/holidays/countries/vietnam.py b/holidays/countries/vietnam.py index 6f4b41cf6..a6777a76d 100644 --- a/holidays/countries/vietnam.py +++ b/holidays/countries/vietnam.py @@ -9,13 +9,11 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import timedelta as td - from holidays.groups import ChineseCalendarHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SAT_SUN_TO_NEXT_WORKDAY -class Vietnam(HolidayBase, ChineseCalendarHolidays, InternationalHolidays): +class Vietnam(ObservedHolidayBase, ChineseCalendarHolidays, InternationalHolidays): """ https://publicholidays.vn/ http://vbpl.vn/TW/Pages/vbpqen-toanvan.aspx?ItemID=11013 Article.115 @@ -23,18 +21,19 @@ class Vietnam(HolidayBase, ChineseCalendarHolidays, InternationalHolidays): """ country = "VN" + observed_label = "%s (Observed)" def __init__(self, *args, **kwargs): ChineseCalendarHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) + super().__init__(observed_rule=SAT_SUN_TO_NEXT_WORKDAY, *args, **kwargs) def _populate(self, year): super()._populate(year) - observed_dates = set() + dts_observed = set() # New Year's Day - observed_dates.add(self._add_new_years_day("International New Year's Day")) + dts_observed.add(self._add_new_years_day("International New Year's Day")) # Lunar New Year self._add_chinese_new_years_eve("Vietnamese New Year's Eve") @@ -47,25 +46,19 @@ def _populate(self, year): # Vietnamese Kings' Commemoration Day # https://en.wikipedia.org/wiki/H%C3%B9ng_Kings%27_Festival if year >= 2007: - observed_dates.add(self._add_hung_kings_day("Hung Kings Commemoration Day")) + dts_observed.add(self._add_hung_kings_day("Hung Kings Commemoration Day")) # Liberation Day/Reunification Day - observed_dates.add(self._add_holiday_apr_30("Liberation Day/Reunification Day")) + dts_observed.add(self._add_holiday_apr_30("Liberation Day/Reunification Day")) # International Labor Day - observed_dates.add(self._add_labor_day("International Labor Day")) + dts_observed.add(self._add_labor_day("International Labor Day")) # Independence Day - observed_dates.add(self._add_holiday_sep_2("Independence Day")) + dts_observed.add(self._add_holiday_sep_2("Independence Day")) if self.observed: - for dt in sorted(observed_dates): - if not self._is_weekend(dt): - continue - next_workday = dt + td(days=+1) - while self._is_weekend(next_workday) or next_workday in observed_dates: - next_workday += td(days=+1) - observed_dates.add(self._add_holiday(f"{self[dt]} (Observed)", next_workday)) + self._populate_observed(dts_observed) class VN(Vietnam): diff --git a/holidays/countries/zambia.py b/holidays/countries/zambia.py index aa8381d27..6dd4d8398 100644 --- a/holidays/countries/zambia.py +++ b/holidays/countries/zambia.py @@ -9,15 +9,12 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.calendars.gregorian import MAR, JUL, AUG, SEP from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON -class Zambia(HolidayBase, ChristianHolidays, InternationalHolidays): +class Zambia(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://www.officeholidays.com/countries/zambia/ https://www.timeanddate.com/holidays/zambia/ @@ -26,6 +23,7 @@ class Zambia(HolidayBase, ChristianHolidays, InternationalHolidays): """ country = "ZM" + observed_label = "%s (Observed)" special_holidays = { 2016: ( (AUG, 11, "General elections and referendum"), @@ -48,13 +46,7 @@ class Zambia(HolidayBase, ChristianHolidays, InternationalHolidays): def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date) -> None: - # whenever a public holiday falls on a Sunday, - # it rolls over to the following Monday - if self.observed and self._is_sunday(dt): - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=+1)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): # Observed since 1965 @@ -95,10 +87,10 @@ def _populate(self, year): self._add_observed(self._add_africa_day("Africa Freedom Day")) # Heroes' Day. - first_mon_of_july = self._add_holiday_1st_mon_of_jul("Heroes' Day") + self._add_holiday_1st_mon_of_jul("Heroes' Day") # Unity Day. - self._add_holiday("Unity Day", first_mon_of_july + td(days=+1)) + self._add_holiday_1_day_past_1st_mon_of_jul("Unity Day") # Farmers' Day. self._add_holiday_1st_mon_of_aug("Farmers' Day") diff --git a/holidays/countries/zimbabwe.py b/holidays/countries/zimbabwe.py index 968c34911..310299281 100644 --- a/holidays/countries/zimbabwe.py +++ b/holidays/countries/zimbabwe.py @@ -9,29 +9,23 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -from datetime import date -from datetime import timedelta as td - from holidays.groups import ChristianHolidays, InternationalHolidays -from holidays.holiday_base import HolidayBase +from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON, SUN_TO_NEXT_TUE -class Zimbabwe(HolidayBase, ChristianHolidays, InternationalHolidays): +class Zimbabwe(ObservedHolidayBase, ChristianHolidays, InternationalHolidays): """ https://en.wikipedia.org/wiki/Public_holidays_in_Zimbabwe https://en.wikipedia.org/wiki/Robert_Gabriel_Mugabe_National_Youth_Day """ country = "ZW" + observed_label = "%s (Observed)" def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) InternationalHolidays.__init__(self) - super().__init__(*args, **kwargs) - - def _add_observed(self, dt: date, days: int = +1) -> None: - if self.observed and self._is_sunday(dt): - self._add_holiday("%s (Observed)" % self[dt], dt + td(days=days)) + super().__init__(observed_rule=SUN_TO_NEXT_MON, *args, **kwargs) def _populate(self, year): if year <= 1987: @@ -57,9 +51,11 @@ def _populate(self, year): # Easter Monday. self._add_easter_monday("Easter Monday") - # Independence Day. - apr_18 = self._add_holiday_apr_18("Independence Day") - self._add_observed(apr_18, days=+2 if apr_18 == self._easter_sunday else +1) + self._add_observed( + # Independence Day. + apr_18 := self._add_holiday_apr_18("Independence Day"), + rule=SUN_TO_NEXT_TUE if apr_18 == self._easter_sunday else SUN_TO_NEXT_MON, + ) # Workers' Day. self._add_observed(self._add_labor_day("Workers' Day")) @@ -68,16 +64,16 @@ def _populate(self, year): self._add_observed(self._add_africa_day("Africa Day")) # Zimbabwe Heroes' Day. - second_mon_of_august = self._add_holiday_2nd_mon_of_aug("Zimbabwe Heroes' Day") + self._add_holiday_2nd_mon_of_aug("Zimbabwe Heroes' Day") # Defense Forces Day. - self._add_holiday("Defense Forces Day", second_mon_of_august + td(days=+1)) + self._add_holiday_1_day_past_2nd_mon_of_aug("Defense Forces Day") # Unity Day. self._add_observed(self._add_holiday_dec_22("Unity Day")) # Christmas Day. - self._add_observed(self._add_christmas_day("Christmas Day"), days=+2) + self._add_observed(self._add_christmas_day("Christmas Day"), rule=SUN_TO_NEXT_TUE) # Boxing Day. self._add_observed(self._add_christmas_day_two("Boxing Day")) diff --git a/holidays/locale/ar/LC_MESSAGES/AE.po b/holidays/locale/ar/LC_MESSAGES/AE.po index 79ea54ba7..ae77928bb 100644 --- a/holidays/locale/ar/LC_MESSAGES/AE.po +++ b/holidays/locale/ar/LC_MESSAGES/AE.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: Python Holidays 0.29\n" "POT-Creation-Date: 2023-06-28 00:13+0100\n" -"PO-Revision-Date: 2023-07-05 17:07+0100\n" -"Last-Translator: \n" -"Language-Team: Abdelkhalek Boukli Hacene \n" +"PO-Revision-Date: 2023-09-12 15:54+0100\n" +"Last-Translator: Abdelkhalek Boukli Hacene \n" +"Language-Team: Python Holidays localization team\n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/holidays/locale/ar/LC_MESSAGES/BH.po b/holidays/locale/ar/LC_MESSAGES/BH.po index 7a93c4dce..18b037bbe 100644 --- a/holidays/locale/ar/LC_MESSAGES/BH.po +++ b/holidays/locale/ar/LC_MESSAGES/BH.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: Python Holidays 0.29\n" "POT-Creation-Date: 2023-06-28 00:13+0100\n" -"PO-Revision-Date: 2023-07-05 17:40+0100\n" -"Last-Translator: \n" -"Language-Team: Abdelkhalek Boukli Hacene \n" +"PO-Revision-Date: 2023-09-12 15:52+0100\n" +"Last-Translator: Abdelkhalek Boukli Hacene \n" +"Language-Team: Python Holidays localization team\n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/holidays/locale/ar/LC_MESSAGES/CA.po b/holidays/locale/ar/LC_MESSAGES/CA.po index d285452e3..e8067485d 100644 --- a/holidays/locale/ar/LC_MESSAGES/CA.po +++ b/holidays/locale/ar/LC_MESSAGES/CA.po @@ -3,10 +3,10 @@ # msgid "" msgstr "" -"Project-Id-Version: Python Holidays 0.26\n" +"Project-Id-Version: Python Holidays 0.32\n" "POT-Creation-Date: 2023-05-20 18:16-0700\n" -"PO-Revision-Date: 2023-05-20 18:30-0700\n" -"Last-Translator: Arkadii Yakovets \n" +"PO-Revision-Date: 2023-08-26 18:25+0300\n" +"Last-Translator: ~Jhellico \n" "Language-Team: Python Holidays localization team\n" "Language: ar\n" "MIME-Version: 1.0\n" @@ -14,8 +14,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n" "Generated-By: Lingua 4.15.0\n" -"X-Generator: Poedit 3.3.1\n" +"X-Generator: Poedit 3.2.2\n" +#. %s (Observed). #, c-format msgid "%s (Observed)" msgstr "(تمت ملاحظته) %s" @@ -52,8 +53,8 @@ msgstr "يوم الملاكمة" msgid "Family Day" msgstr "يوم العائلة" -#. Thanksgiving. -msgid "Thanksgiving" +#. Thanksgiving Day. +msgid "Thanksgiving Day" msgstr "عيد الشكر" #. Funeral of Queen Elizabeth II. @@ -139,3 +140,11 @@ msgstr "عيد القديس جان بابتيست" #. Saskatchewan Day. msgid "Saskatchewan Day" msgstr "يوم ساسكاتشوان" + +#. Orangemen's Day. +msgid "Orangemen's Day" +msgstr "يوم رجال البرتقال" + +#. Natal Day. +msgid "Natal Day" +msgstr "يوم التأسيس" diff --git a/holidays/locale/ar/LC_MESSAGES/DZ.po b/holidays/locale/ar/LC_MESSAGES/DZ.po index 611cbed56..149019c75 100644 --- a/holidays/locale/ar/LC_MESSAGES/DZ.po +++ b/holidays/locale/ar/LC_MESSAGES/DZ.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: Python Holidays 0.29\n" "POT-Creation-Date: 2023-06-28 00:13+0100\n" -"PO-Revision-Date: 2023-07-05 17:40+0100\n" -"Last-Translator: \n" -"Language-Team: Abdelkhalek Boukli Hacene \n" +"PO-Revision-Date: 2023-09-12 14:56+0100\n" +"Last-Translator: Abdelkhalek Boukli Hacene \n" +"Language-Team: Python Holidays localization team\n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -24,48 +24,46 @@ msgstr "" msgid "رأس السنة الميلادية" msgstr "" -#. Amazigh New Year / Yennayer +#. Amazigh New Year / Yennayer. msgid "رأس السنة الأمازيغية" msgstr "" -#. Labour Day +#. Labor Day. msgid "عيد العمال" msgstr "" -#. Independence Day +#. Independence Day. msgid "عيد الإستقلال" msgstr "" -#. Revolution Day +#. Revolution Day. msgid "عيد الثورة" msgstr "" -#. Islamic New Year +#. Islamic New Year. msgid "رأس السنة الهجرية" msgstr "" -#. Ashura +#. Ashura. msgid "عاشورة" msgstr "" -#. Mawlid / Prophet's Birthday +#. Mawlid / Prophet's Birthday. msgid "عيد المولد النبوي" msgstr "" -#. As of April 30, 2023. Algeria has 3 days of Eid holidays -#. (https://www.horizons.dz/english/archives/amp/12021) Eid al-Fitr - Feast -#. Festive +#. Eid al-Fitr - Feast Festive. msgid "عيد الفطر" msgstr "" -#. Eid al-Fitr Holiday +#. Eid al-Fitr Holiday. msgid "عطلة عيد الفطر" msgstr "" -#. Eid al-Adha - Scarfice Festive +#. Eid al-Adha - Scarfice Festive. msgid "عيد الأضحى" msgstr "" -#. Eid al-Adha Holiday +#. Eid al-Adha Holiday. msgid "عطلة عيد الأضحى" msgstr "" diff --git a/holidays/locale/ar/LC_MESSAGES/EG.po b/holidays/locale/ar/LC_MESSAGES/EG.po index 4f0b2a020..a930434b5 100644 --- a/holidays/locale/ar/LC_MESSAGES/EG.po +++ b/holidays/locale/ar/LC_MESSAGES/EG.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: Python Holidays 0.29\n" "POT-Creation-Date: 2023-06-28 00:13+0100\n" -"PO-Revision-Date: 2023-07-11 02:08+0100\n" -"Last-Translator: \n" -"Language-Team: Abdelkhalek Boukli Hacene \n" +"PO-Revision-Date: 2023-09-12 15:50+0100\n" +"Last-Translator: Abdelkhalek Boukli Hacene \n" +"Language-Team: Python Holidays localization team\n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/holidays/locale/ar/LC_MESSAGES/TN.po b/holidays/locale/ar/LC_MESSAGES/TN.po index 6e8238ff9..2619e6de2 100644 --- a/holidays/locale/ar/LC_MESSAGES/TN.po +++ b/holidays/locale/ar/LC_MESSAGES/TN.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: Python Holidays 0.29\n" "POT-Creation-Date: 2023-06-28 00:13+0100\n" -"PO-Revision-Date: 2023-07-05 17:41+0100\n" -"Last-Translator: \n" -"Language-Team: Abdelkhalek Boukli Hacene \n" +"PO-Revision-Date: 2023-09-12 15:48+0100\n" +"Last-Translator: Abdelkhalek Boukli Hacene \n" +"Language-Team: Python Holidays localization team\n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/holidays/locale/ar/LC_MESSAGES/UA.po b/holidays/locale/ar/LC_MESSAGES/UA.po index b626650f2..f7c6b42fe 100644 --- a/holidays/locale/ar/LC_MESSAGES/UA.po +++ b/holidays/locale/ar/LC_MESSAGES/UA.po @@ -25,6 +25,7 @@ msgstr "%d/%m/%Y" msgid "Вихідний день (перенесено з %s)" msgstr "يوم عطلة (استبدل من %s)" +#. %s (Observed). #, c-format msgid "%s (вихідний)" msgstr "(يوم عطلة) %s" diff --git a/holidays/locale/bg/LC_MESSAGES/BG.po b/holidays/locale/bg/LC_MESSAGES/BG.po index 6b377b076..4e77e0142 100644 --- a/holidays/locale/bg/LC_MESSAGES/BG.po +++ b/holidays/locale/bg/LC_MESSAGES/BG.po @@ -66,6 +66,7 @@ msgstr "" msgid "Рождество Христово" msgstr "" +#. %s (Observed). #, c-format msgid "%s (почивен ден)" msgstr "" diff --git a/holidays/locale/bs/LC_MESSAGES/BA.po b/holidays/locale/bs/LC_MESSAGES/BA.po index 2c0b94ebe..66c6d3e29 100644 --- a/holidays/locale/bs/LC_MESSAGES/BA.po +++ b/holidays/locale/bs/LC_MESSAGES/BA.po @@ -16,6 +16,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.2.2\n" +#. %s (Observed). #, c-format msgid "%s (preneseno)" msgstr "" diff --git a/holidays/locale/de/LC_MESSAGES/BE.po b/holidays/locale/de/LC_MESSAGES/BE.po index 55050d83c..6cdbf7f7e 100644 --- a/holidays/locale/de/LC_MESSAGES/BE.po +++ b/holidays/locale/de/LC_MESSAGES/BE.po @@ -3,9 +3,9 @@ # msgid "" msgstr "" -"Project-Id-Version: Python Holidays 0.28\n" +"Project-Id-Version: Python Holidays 0.33\n" "POT-Creation-Date: 2023-06-27 13:17+0300\n" -"PO-Revision-Date: 2023-06-28 15:14+0300\n" +"PO-Revision-Date: 2023-09-06 20:49+0300\n" "Last-Translator: ~Jhellico \n" "Language-Team: Python Holidays localization team\n" "Language: de\n" @@ -33,7 +33,7 @@ msgid "Dag van de Arbeid" msgstr "Tag der Arbeit" #. Ascension Day. -msgid "Hemelvaart" +msgid "O. L. H. Hemelvaart" msgstr "Christi Himmelfahrt" #. Whit Sunday. @@ -49,7 +49,7 @@ msgid "Nationale feestdag" msgstr "Nationalfeiertag" #. Assumption of Mary. -msgid "Onze Lieve Vrouw hemelvaart" +msgid "O. L. V. Hemelvaart" msgstr "Mariä Himmelfahrt" #. All Saints' Day. @@ -63,3 +63,15 @@ msgstr "Waffenstillstand" #. Christmas Day. msgid "Kerstmis" msgstr "Weihnachten" + +#. Good Friday. +msgid "Goede Vrijdag" +msgstr "Karfreitag" + +#. Friday after Ascension Day. +msgid "Vrijdag na O. L. H. Hemelvaart" +msgstr "Freitag nach Christi Himmelfahrt" + +#. Bank Holiday. +msgid "Banksluitingsdag" +msgstr "Bankschlusstag" diff --git a/holidays/locale/en/LC_MESSAGES/CA.po b/holidays/locale/en/LC_MESSAGES/CA.po index 38d491493..486136783 100644 --- a/holidays/locale/en/LC_MESSAGES/CA.po +++ b/holidays/locale/en/LC_MESSAGES/CA.po @@ -3,9 +3,9 @@ # msgid "" msgstr "" -"Project-Id-Version: Python Holidays 0.20\n" +"Project-Id-Version: Python Holidays 0.32\n" "POT-Creation-Date: 2023-04-10 14:10+0300\n" -"PO-Revision-Date: 2023-04-10 14:11+0300\n" +"PO-Revision-Date: 2023-08-26 18:22+0300\n" "Last-Translator: ~Jhellico \n" "Language-Team: Python Holidays localization team\n" "Language: en\n" @@ -16,6 +16,7 @@ msgstr "" "Generated-By: Lingua 4.15.0\n" "X-Generator: Poedit 3.2.2\n" +#. %s (Observed). #, c-format msgid "%s (Observed)" msgstr "" @@ -52,8 +53,8 @@ msgstr "" msgid "Family Day" msgstr "" -#. Thanksgiving. -msgid "Thanksgiving" +#. Thanksgiving Day. +msgid "Thanksgiving Day" msgstr "" #. Funeral of Queen Elizabeth II. @@ -139,3 +140,11 @@ msgstr "" #. Saskatchewan Day. msgid "Saskatchewan Day" msgstr "" + +#. Orangemen's Day. +msgid "Orangemen's Day" +msgstr "" + +#. Natal Day. +msgid "Natal Day" +msgstr "" diff --git a/holidays/locale/en_US/LC_MESSAGES/AE.po b/holidays/locale/en_US/LC_MESSAGES/AE.po index 3c430f2ad..3e28ebed2 100644 --- a/holidays/locale/en_US/LC_MESSAGES/AE.po +++ b/holidays/locale/en_US/LC_MESSAGES/AE.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: Python Holidays 0.29\n" "POT-Creation-Date: 2023-06-28 00:13+0100\n" -"PO-Revision-Date: 2023-07-11 03:42+0100\n" -"Last-Translator: \n" -"Language-Team: Abdelkhalek Boukli Hacene \n" +"PO-Revision-Date: 2023-09-12 15:59+0100\n" +"Last-Translator: Abdelkhalek Boukli Hacene \n" +"Language-Team: Python Holidays localization team\n" "Language: en_US\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/holidays/locale/en_US/LC_MESSAGES/AO.po b/holidays/locale/en_US/LC_MESSAGES/AO.po index 31befd5f2..382f9f183 100644 --- a/holidays/locale/en_US/LC_MESSAGES/AO.po +++ b/holidays/locale/en_US/LC_MESSAGES/AO.po @@ -20,7 +20,7 @@ msgstr "" msgid "Dia de eleições gerais" msgstr "General Election Day" -#. Day off for %s. +#. %s (Observed). #, c-format msgid "%s (Ponte)" msgstr "Day off for %s" diff --git a/holidays/locale/en_US/LC_MESSAGES/AR.po b/holidays/locale/en_US/LC_MESSAGES/AR.po index f84130885..ecf07494c 100644 --- a/holidays/locale/en_US/LC_MESSAGES/AR.po +++ b/holidays/locale/en_US/LC_MESSAGES/AR.po @@ -122,6 +122,7 @@ msgstr "Columbus day" msgid "Día de la Soberanía Nacional" msgstr "National Sovereignty Day" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "%s (Observed)" diff --git a/holidays/locale/en_US/LC_MESSAGES/BA.po b/holidays/locale/en_US/LC_MESSAGES/BA.po index 0ffa33669..6d8ebe842 100644 --- a/holidays/locale/en_US/LC_MESSAGES/BA.po +++ b/holidays/locale/en_US/LC_MESSAGES/BA.po @@ -16,6 +16,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.2.2\n" +#. %s (Observed). #, c-format msgid "%s (preneseno)" msgstr "%s (Observed)" diff --git a/holidays/locale/en_US/LC_MESSAGES/BE.po b/holidays/locale/en_US/LC_MESSAGES/BE.po index 91cc7b736..8f935f878 100644 --- a/holidays/locale/en_US/LC_MESSAGES/BE.po +++ b/holidays/locale/en_US/LC_MESSAGES/BE.po @@ -3,9 +3,9 @@ # msgid "" msgstr "" -"Project-Id-Version: Python Holidays 0.28\n" +"Project-Id-Version: Python Holidays 0.33\n" "POT-Creation-Date: 2023-06-27 13:17+0300\n" -"PO-Revision-Date: 2023-06-27 13:44+0300\n" +"PO-Revision-Date: 2023-09-06 20:47+0300\n" "Last-Translator: ~Jhellico \n" "Language-Team: Python Holidays localization team\n" "Language: en_US\n" @@ -33,7 +33,7 @@ msgid "Dag van de Arbeid" msgstr "Labor Day" #. Ascension Day. -msgid "Hemelvaart" +msgid "O. L. H. Hemelvaart" msgstr "Ascension Day" #. Whit Sunday. @@ -49,7 +49,7 @@ msgid "Nationale feestdag" msgstr "National Day" #. Assumption of Mary. -msgid "Onze Lieve Vrouw hemelvaart" +msgid "O. L. V. Hemelvaart" msgstr "Assumption of Mary" #. All Saints' Day. @@ -63,3 +63,15 @@ msgstr "Armistice Day" #. Christmas Day. msgid "Kerstmis" msgstr "Christmas Day" + +#. Good Friday. +msgid "Goede Vrijdag" +msgstr "Good Friday" + +#. Friday after Ascension Day. +msgid "Vrijdag na O. L. H. Hemelvaart" +msgstr "Friday after Ascension Day" + +#. Bank Holiday. +msgid "Banksluitingsdag" +msgstr "Bank Holiday" diff --git a/holidays/locale/en_US/LC_MESSAGES/BG.po b/holidays/locale/en_US/LC_MESSAGES/BG.po index d6735ed45..f40f177ef 100644 --- a/holidays/locale/en_US/LC_MESSAGES/BG.po +++ b/holidays/locale/en_US/LC_MESSAGES/BG.po @@ -66,6 +66,7 @@ msgstr "Christmas Eve" msgid "Рождество Христово" msgstr "Christmas Day" +#. %s (Observed). #, c-format msgid "%s (почивен ден)" msgstr "%s (Observed)" diff --git a/holidays/locale/en_US/LC_MESSAGES/BH.po b/holidays/locale/en_US/LC_MESSAGES/BH.po index 8659d68c3..98dbb8deb 100644 --- a/holidays/locale/en_US/LC_MESSAGES/BH.po +++ b/holidays/locale/en_US/LC_MESSAGES/BH.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: Python Holidays 0.29\n" "POT-Creation-Date: 2023-06-28 00:13+0100\n" -"PO-Revision-Date: 2023-07-11 03:43+0100\n" -"Last-Translator: \n" -"Language-Team: Abdelkhalek Boukli Hacene \n" +"PO-Revision-Date: 2023-09-12 16:02+0100\n" +"Last-Translator: Abdelkhalek Boukli Hacene \n" +"Language-Team: Python Holidays localization team\n" "Language: en_US\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/holidays/locale/en_US/LC_MESSAGES/CO.po b/holidays/locale/en_US/LC_MESSAGES/CO.po index cb4a18658..dbf11fd47 100644 --- a/holidays/locale/en_US/LC_MESSAGES/CO.po +++ b/holidays/locale/en_US/LC_MESSAGES/CO.po @@ -88,6 +88,7 @@ msgstr "Corpus Christi" msgid "Sagrado Corazón" msgstr "Sacred Heart" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "%s (Observed)" diff --git a/holidays/locale/en_US/LC_MESSAGES/CR.po b/holidays/locale/en_US/LC_MESSAGES/CR.po index f55a3698a..b10592fca 100644 --- a/holidays/locale/en_US/LC_MESSAGES/CR.po +++ b/holidays/locale/en_US/LC_MESSAGES/CR.po @@ -16,6 +16,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.3\n" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "%s (Observed)" diff --git a/holidays/locale/en_US/LC_MESSAGES/CU.po b/holidays/locale/en_US/LC_MESSAGES/CU.po index 686355972..32c384eb6 100644 --- a/holidays/locale/en_US/LC_MESSAGES/CU.po +++ b/holidays/locale/en_US/LC_MESSAGES/CU.po @@ -16,6 +16,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.2.2\n" +#. %s Observed. #, c-format msgid "%s (Observado)" msgstr "%s (Observed)" diff --git a/holidays/locale/en_US/LC_MESSAGES/DZ.po b/holidays/locale/en_US/LC_MESSAGES/DZ.po index 25fa5231a..b64648f21 100644 --- a/holidays/locale/en_US/LC_MESSAGES/DZ.po +++ b/holidays/locale/en_US/LC_MESSAGES/DZ.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: Python Holidays 0.29\n" "POT-Creation-Date: 2023-06-28 00:13+0100\n" -"PO-Revision-Date: 2023-07-11 03:43+0100\n" -"Last-Translator: \n" -"Language-Team: Abdelkhalek Boukli Hacene \n" +"PO-Revision-Date: 2023-09-12 14:56+0100\n" +"Last-Translator: Abdelkhalek Boukli Hacene \n" +"Language-Team: Python Holidays localization team\n" "Language: en_US\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -25,48 +25,46 @@ msgstr "%s* (*estimated)" msgid "رأس السنة الميلادية" msgstr "New Year's Day" -#. Amazigh New Year / Yennayer +#. Amazigh New Year / Yennayer. msgid "رأس السنة الأمازيغية" msgstr "Amazigh New Year" -#. Labour Day +#. Labor Day. msgid "عيد العمال" msgstr "Labor Day" -#. Independence Day +#. Independence Day. msgid "عيد الإستقلال" msgstr "Independence Day" -#. Revolution Day +#. Revolution Day. msgid "عيد الثورة" msgstr "Revolution Day" -#. Islamic New Year +#. Islamic New Year. msgid "رأس السنة الهجرية" msgstr "Islamic New Year" -#. Ashura +#. Ashura. msgid "عاشورة" msgstr "Ashura" -#. Mawlid / Prophet's Birthday +#. Mawlid / Prophet's Birthday. msgid "عيد المولد النبوي" msgstr "Prophet's Birthday" -#. As of April 30, 2023. Algeria has 3 days of Eid holidays -#. (https://www.horizons.dz/english/archives/amp/12021) Eid al-Fitr - Feast -#. Festive +#. Eid al-Fitr - Feast Festive. msgid "عيد الفطر" msgstr "Eid al-Fitr" -#. Eid al-Fitr Holiday +#. Eid al-Fitr Holiday. msgid "عطلة عيد الفطر" msgstr "Eid al-Fitr Holiday" -#. Eid al-Adha - Scarfice Festive +#. Eid al-Adha - Scarfice Festive. msgid "عيد الأضحى" msgstr "Eid al-Adha" -#. Eid al-Adha Holiday +#. Eid al-Adha Holiday. msgid "عطلة عيد الأضحى" msgstr "Eid al-Adha Holiday" diff --git a/holidays/locale/en_US/LC_MESSAGES/EC.po b/holidays/locale/en_US/LC_MESSAGES/EC.po index 7effaed68..1e6ed6d6c 100644 --- a/holidays/locale/en_US/LC_MESSAGES/EC.po +++ b/holidays/locale/en_US/LC_MESSAGES/EC.po @@ -56,6 +56,7 @@ msgstr "Independence of Cuenca" msgid "Día de Navidad" msgstr "Christmas Day" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "%s (Observed)" diff --git a/holidays/locale/en_US/LC_MESSAGES/EG.po b/holidays/locale/en_US/LC_MESSAGES/EG.po index 3b7ef2b42..5ece5ad09 100644 --- a/holidays/locale/en_US/LC_MESSAGES/EG.po +++ b/holidays/locale/en_US/LC_MESSAGES/EG.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: Python Holidays 0.29\n" "POT-Creation-Date: 2023-06-28 00:13+0100\n" -"PO-Revision-Date: 2023-07-11 02:08+0100\n" -"Last-Translator: \n" -"Language-Team: Abdelkhalek Boukli Hacene \n" +"PO-Revision-Date: 2023-09-12 16:05+0100\n" +"Last-Translator: Abdelkhalek Boukli Hacene \n" +"Language-Team: Python Holidays localization team\n" "Language: en_US\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/holidays/locale/en_US/LC_MESSAGES/LV.po b/holidays/locale/en_US/LC_MESSAGES/LV.po index dbd1db111..ea05f6e7a 100644 --- a/holidays/locale/en_US/LC_MESSAGES/LV.po +++ b/holidays/locale/en_US/LC_MESSAGES/LV.po @@ -33,6 +33,7 @@ msgstr "" "Day the Latvian hockey team won the bronze medal at the 2023 World Ice " "Hockey Championship" +#. %s (Observed). #, c-format msgid "%s (brīvdiena)" msgstr "%s (Observed)" diff --git a/holidays/locale/en_US/LC_MESSAGES/MC.po b/holidays/locale/en_US/LC_MESSAGES/MC.po index eea048d13..2b0f39d1d 100644 --- a/holidays/locale/en_US/LC_MESSAGES/MC.po +++ b/holidays/locale/en_US/LC_MESSAGES/MC.po @@ -16,9 +16,11 @@ msgstr "" "Generated-By: Lingua 4.15.0\n" "X-Generator: Poedit 3.2.2\n" +#. Public holiday. msgid "Jour férié" msgstr "Public holiday" +#. %s (Observed). #, c-format msgid "%s (Observé)" msgstr "%s (Observed)" diff --git a/holidays/locale/en_US/LC_MESSAGES/RS.po b/holidays/locale/en_US/LC_MESSAGES/RS.po index 0f901eb23..b8fc64cf3 100644 --- a/holidays/locale/en_US/LC_MESSAGES/RS.po +++ b/holidays/locale/en_US/LC_MESSAGES/RS.po @@ -51,6 +51,7 @@ msgstr "Easter Sunday" msgid "Други дан Васкрса" msgstr "Easter Monday" +#. %s (Observed). #, c-format msgid "%s (слободан дан)" msgstr "%s (Observed)" diff --git a/holidays/locale/en_US/LC_MESSAGES/TH.po b/holidays/locale/en_US/LC_MESSAGES/TH.po index 98f3b025d..fd244b5b3 100644 --- a/holidays/locale/en_US/LC_MESSAGES/TH.po +++ b/holidays/locale/en_US/LC_MESSAGES/TH.po @@ -3,7 +3,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Python Holidays 0.20\n" +"Project-Id-Version: Python Holidays 0.33\n" "POT-Creation-Date: 2023-03-18 15:58-0700\n" "PO-Revision-Date: \n" "Last-Translator: PPsyrius \n" @@ -67,7 +67,7 @@ msgstr "HM King Maha Vajiralongkorn's Coronation Celebrations" msgid "ชดเชยวันสงกรานต์" msgstr "Songkran Festival (in lieu)" -#. %s (in lieu) +#. %s (in lieu). #, c-format msgid "ชดเชย%s" msgstr "%s (in lieu)" @@ -80,6 +80,10 @@ msgstr "New Year's Day" msgid "วันสิ้นปี" msgstr "New Year's Eve" +#. National Children's Day +msgid "วันเด็กแห่งชาติ" +msgstr "National Children's Day" + #. Chakri Memorial Day. msgid "วันจักรี" msgstr "Chakri Memorial Day" @@ -100,6 +104,7 @@ msgstr "National Day" msgid "วันฉัตรมงคล" msgstr "Coronation Day" +#. HM Queen Suthida's Birthday. msgid "" "วันเฉลิมพระชนมพรรษาสมเด็จพระนางเจ้าสุทิดา พัชรสุธาพิมลลักษณ พระบรมราชินี" msgstr "HM Queen Suthida's Birthday" @@ -176,6 +181,62 @@ msgstr "Asarnha Bucha" msgid "วันเข้าพรรษา" msgstr "Buddhist Lent Day" +#. Royal Thai Armed Forces Day +msgid "วันกองทัพไทย" +msgstr "Royal Thai Armed Forces Day" + +#. Additional Closing Day for Bank for Agriculture and Agricultural +#. Cooperatives +msgid "" +"วันหยุดเพิ่มเติมสำหรับการปิดบัญชีประจำปีของธนาคารเพื่อการเกษตรและสหกรณ์การเกษตร" +msgstr "" +"Additional Closing Day for Bank for Agriculture and Agricultural " +"Cooperatives" + +#. Mid-Year Closing Day +msgid "วันหยุดภาคครึ่งปีของสถาบันการเงินและสถาบันการเงินเฉพาะกิจ" +msgstr "Mid-Year Closing Day" + #. Royal Ploughing Ceremony. msgid "วันพืชมงคล" msgstr "Royal Ploughing Ceremony" + +#. Teacher's Day +msgid "วันครู" +msgstr "Teacher's Day" + +#. National Aviation Day +msgid "วันการบินแห่งชาติ" +msgstr "National Aviation Day" + +#. National Forest Conservation Day +msgid "วันอนุรักษ์ทรัพยากรป่าไม้ของชาติ" +msgstr "National Forest Conservation Day" + +#. National Artist Day +msgid "วันศิลปินแห่งชาติ" +msgstr "National Artist Day" + +#. International Women's Day +msgid "วันสตรีสากล" +msgstr "International Women's Day" + +#. Loy Krathong +msgid "วันลอยกระทง" +msgstr "Loy Krathong" + +#. Thai Veterans Day +msgid "วันทหารผ่านศึก" +msgstr "Thai Veterans Day" + +#. National Science Day +msgid "วันวิทยาศาสตร์แห่งชาติ" +msgstr "National Science Day" + +#. HM King Ramkamhaeng Memorial Day +msgid "วันพ่อขุนรามคำแหงมหาราช" +msgstr "HM King Ramkamhaeng Memorial Day" + +#. Thai National Flag Day +msgid "วันพระราชทานธงชาติไทย" +msgstr "Thai National Flag Day" diff --git a/holidays/locale/en_US/LC_MESSAGES/TN.po b/holidays/locale/en_US/LC_MESSAGES/TN.po index 7da068c10..df784f678 100644 --- a/holidays/locale/en_US/LC_MESSAGES/TN.po +++ b/holidays/locale/en_US/LC_MESSAGES/TN.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: Python Holidays 0.29\n" "POT-Creation-Date: 2023-06-28 00:13+0100\n" -"PO-Revision-Date: 2023-07-11 03:44+0100\n" -"Last-Translator: \n" -"Language-Team: Abdelkhalek Boukli Hacene \n" +"PO-Revision-Date: 2023-09-12 16:08+0100\n" +"Last-Translator: Abdelkhalek Boukli Hacene \n" +"Language-Team: Python Holidays localization team\n" "Language: en_US\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/holidays/locale/en_US/LC_MESSAGES/UA.po b/holidays/locale/en_US/LC_MESSAGES/UA.po index 6f0367809..cbcc910be 100644 --- a/holidays/locale/en_US/LC_MESSAGES/UA.po +++ b/holidays/locale/en_US/LC_MESSAGES/UA.po @@ -26,6 +26,7 @@ msgstr "%m/%d/%Y" msgid "Вихідний день (перенесено з %s)" msgstr "Day off (substituted from %s)" +#. %s (Observed). #, c-format msgid "%s (вихідний)" msgstr "%s (Observed)" diff --git a/holidays/locale/es/LC_MESSAGES/AR.po b/holidays/locale/es/LC_MESSAGES/AR.po index 56417df97..fa8953b34 100644 --- a/holidays/locale/es/LC_MESSAGES/AR.po +++ b/holidays/locale/es/LC_MESSAGES/AR.po @@ -118,6 +118,7 @@ msgstr "" msgid "Día de la Soberanía Nacional" msgstr "" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "" diff --git a/holidays/locale/es/LC_MESSAGES/CO.po b/holidays/locale/es/LC_MESSAGES/CO.po index 696c6f97e..2e9c002fe 100644 --- a/holidays/locale/es/LC_MESSAGES/CO.po +++ b/holidays/locale/es/LC_MESSAGES/CO.po @@ -88,6 +88,7 @@ msgstr "" msgid "Sagrado Corazón" msgstr "" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "" diff --git a/holidays/locale/es/LC_MESSAGES/CR.po b/holidays/locale/es/LC_MESSAGES/CR.po index 6440d4202..00b691441 100644 --- a/holidays/locale/es/LC_MESSAGES/CR.po +++ b/holidays/locale/es/LC_MESSAGES/CR.po @@ -16,6 +16,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.3\n" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "" diff --git a/holidays/locale/es/LC_MESSAGES/CU.po b/holidays/locale/es/LC_MESSAGES/CU.po index b5ffe707c..03eb51b3d 100644 --- a/holidays/locale/es/LC_MESSAGES/CU.po +++ b/holidays/locale/es/LC_MESSAGES/CU.po @@ -16,6 +16,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.2.2\n" +#. %s Observed. #, c-format msgid "%s (Observado)" msgstr "" diff --git a/holidays/locale/es/LC_MESSAGES/EC.po b/holidays/locale/es/LC_MESSAGES/EC.po index 0cd4c5da8..fb6b0e850 100644 --- a/holidays/locale/es/LC_MESSAGES/EC.po +++ b/holidays/locale/es/LC_MESSAGES/EC.po @@ -56,6 +56,7 @@ msgstr "" msgid "Día de Navidad" msgstr "" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "" diff --git a/holidays/locale/fr/LC_MESSAGES/BE.po b/holidays/locale/fr/LC_MESSAGES/BE.po index a1d6aaae4..a1965e87d 100644 --- a/holidays/locale/fr/LC_MESSAGES/BE.po +++ b/holidays/locale/fr/LC_MESSAGES/BE.po @@ -3,9 +3,9 @@ # msgid "" msgstr "" -"Project-Id-Version: Python Holidays 0.28\n" +"Project-Id-Version: Python Holidays 0.33\n" "POT-Creation-Date: 2023-06-27 13:17+0300\n" -"PO-Revision-Date: 2023-06-28 15:28+0300\n" +"PO-Revision-Date: 2023-09-06 20:51+0300\n" "Last-Translator: ~Jhellico \n" "Language-Team: Python Holidays localization team\n" "Language: fr\n" @@ -33,7 +33,7 @@ msgid "Dag van de Arbeid" msgstr "Fête du Travail" #. Ascension Day. -msgid "Hemelvaart" +msgid "O. L. H. Hemelvaart" msgstr "Ascension" #. Whit Sunday. @@ -49,7 +49,7 @@ msgid "Nationale feestdag" msgstr "Fête nationale" #. Assumption of Mary. -msgid "Onze Lieve Vrouw hemelvaart" +msgid "O. L. V. Hemelvaart" msgstr "Assomption" #. All Saints' Day. @@ -63,3 +63,15 @@ msgstr "Jour de l'Armistice" #. Christmas Day. msgid "Kerstmis" msgstr "Noël" + +#. Good Friday. +msgid "Goede Vrijdag" +msgstr "Vendredi Saint" + +#. Friday after Ascension Day. +msgid "Vrijdag na O. L. H. Hemelvaart" +msgstr "Vendredi suivant l'Ascension" + +#. Bank Holiday. +msgid "Banksluitingsdag" +msgstr "Jour de fermeture bancaire" diff --git a/holidays/locale/fr/LC_MESSAGES/CA.po b/holidays/locale/fr/LC_MESSAGES/CA.po index 747681cc6..dcf3eab2c 100644 --- a/holidays/locale/fr/LC_MESSAGES/CA.po +++ b/holidays/locale/fr/LC_MESSAGES/CA.po @@ -3,9 +3,9 @@ # msgid "" msgstr "" -"Project-Id-Version: Python Holidays 0.21\n" +"Project-Id-Version: Python Holidays 0.32\n" "POT-Creation-Date: 2023-04-10 14:10+0300\n" -"PO-Revision-Date: 2023-04-10 14:11+0300\n" +"PO-Revision-Date: 2023-08-26 18:23+0300\n" "Last-Translator: ~Jhellico \n" "Language-Team: Python Holidays localization team\n" "Language: fr\n" @@ -16,6 +16,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.2.2\n" +#. %s (Observed). #, c-format msgid "%s (Observed)" msgstr "%s (Observé)" @@ -52,8 +53,8 @@ msgstr "Boxing Day" msgid "Family Day" msgstr "Fête de la famille" -#. Thanksgiving. -msgid "Thanksgiving" +#. Thanksgiving Day. +msgid "Thanksgiving Day" msgstr "Action de grâce" #. Funeral of Queen Elizabeth II. @@ -139,3 +140,11 @@ msgstr "Fête nationale du Québec" #. Saskatchewan Day. msgid "Saskatchewan Day" msgstr "Jour du Saskatchewan" + +#. Orangemen's Day. +msgid "Orangemen's Day" +msgstr "Journée des Orangistes" + +#. Natal Day. +msgid "Natal Day" +msgstr "Jour de la Fondation" diff --git a/holidays/locale/fr/LC_MESSAGES/DZ.po b/holidays/locale/fr/LC_MESSAGES/DZ.po new file mode 100644 index 000000000..7a9214eaf --- /dev/null +++ b/holidays/locale/fr/LC_MESSAGES/DZ.po @@ -0,0 +1,70 @@ +# Algeria holidays fr localization. +# Authors: Abdelkhalek Boukli Hacene , 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: Python Holidays 0.33\n" +"POT-Creation-Date: 2023-06-28 00:13+0100\n" +"PO-Revision-Date: 2023-09-12 15:08+0100\n" +"Last-Translator: Abdelkhalek Boukli Hacene \n" +"Language-Team: Python Holidays localization team\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"Generated-By: Lingua 4.15.0\n" +"X-Generator: Poedit 3.3.2\n" + +#. Estimated label. +#, c-format +msgid "(تقدير*) *%s" +msgstr "%s* (*estimé)" + +#. New Year's Day. +msgid "رأس السنة الميلادية" +msgstr "Nouvel an" + +#. Amazigh New Year / Yennayer. +msgid "رأس السنة الأمازيغية" +msgstr "Nouvel an Amazigh" + +#. Labor Day. +msgid "عيد العمال" +msgstr "Fête du Travail" + +#. Independence Day. +msgid "عيد الإستقلال" +msgstr "Fête de l'indépendance" + +#. Revolution Day. +msgid "عيد الثورة" +msgstr "Fête de la Révolution" + +#. Islamic New Year. +msgid "رأس السنة الهجرية" +msgstr "Nouvel an musulman" + +#. Ashura. +msgid "عاشورة" +msgstr "Achoura" + +#. Mawlid / Prophet's Birthday. +msgid "عيد المولد النبوي" +msgstr "Anniversaire du prophète" + +#. Eid al-Fitr - Feast Festive. +msgid "عيد الفطر" +msgstr "Fête de la rupture du jeûne" + +#. Eid al-Fitr Holiday. +msgid "عطلة عيد الفطر" +msgstr "Congé de fête de la rupture du jeûne" + +#. Eid al-Adha - Scarfice Festive. +msgid "عيد الأضحى" +msgstr "Fête du sacrifice" + +#. Eid al-Adha Holiday. +msgid "عطلة عيد الأضحى" +msgstr "Congé de fête du sacrifice" diff --git a/holidays/locale/fr/LC_MESSAGES/MC.po b/holidays/locale/fr/LC_MESSAGES/MC.po index 050c731a1..511e016c3 100644 --- a/holidays/locale/fr/LC_MESSAGES/MC.po +++ b/holidays/locale/fr/LC_MESSAGES/MC.po @@ -16,9 +16,11 @@ msgstr "" "Generated-By: Lingua 4.15.0\n" "X-Generator: Poedit 3.2.2\n" +#. Public holiday. msgid "Jour férié" msgstr "" +#. %s (Observed). #, c-format msgid "%s (Observé)" msgstr "" diff --git a/holidays/locale/lv/LC_MESSAGES/LV.po b/holidays/locale/lv/LC_MESSAGES/LV.po index 6cceae5d1..ae20fd01d 100644 --- a/holidays/locale/lv/LC_MESSAGES/LV.po +++ b/holidays/locale/lv/LC_MESSAGES/LV.po @@ -31,6 +31,7 @@ msgid "" " hokeja čempionātā" msgstr "" +#. %s (Observed). #, c-format msgid "%s (brīvdiena)" msgstr "" diff --git a/holidays/locale/nl/LC_MESSAGES/BE.po b/holidays/locale/nl/LC_MESSAGES/BE.po index 2f1498021..004398c73 100644 --- a/holidays/locale/nl/LC_MESSAGES/BE.po +++ b/holidays/locale/nl/LC_MESSAGES/BE.po @@ -3,9 +3,9 @@ # msgid "" msgstr "" -"Project-Id-Version: Python Holidays 0.28\n" +"Project-Id-Version: Python Holidays 0.33\n" "POT-Creation-Date: 2023-06-27 13:17+0300\n" -"PO-Revision-Date: 2023-06-27 13:41+0300\n" +"PO-Revision-Date: 2023-09-06 20:46+0300\n" "Last-Translator: ~Jhellico \n" "Language-Team: Python Holidays localization team\n" "Language: nl\n" @@ -33,7 +33,7 @@ msgid "Dag van de Arbeid" msgstr "" #. Ascension Day. -msgid "Hemelvaart" +msgid "O. L. H. Hemelvaart" msgstr "" #. Whit Sunday. @@ -49,7 +49,7 @@ msgid "Nationale feestdag" msgstr "" #. Assumption of Mary. -msgid "Onze Lieve Vrouw hemelvaart" +msgid "O. L. V. Hemelvaart" msgstr "" #. All Saints' Day. @@ -63,3 +63,15 @@ msgstr "" #. Christmas Day. msgid "Kerstmis" msgstr "" + +#. Good Friday. +msgid "Goede Vrijdag" +msgstr "" + +#. Friday after Ascension Day. +msgid "Vrijdag na O. L. H. Hemelvaart" +msgstr "" + +#. Bank Holiday. +msgid "Banksluitingsdag" +msgstr "" diff --git a/holidays/locale/pt_AO/LC_MESSAGES/AO.po b/holidays/locale/pt_AO/LC_MESSAGES/AO.po index 32f281b04..1c98775fb 100644 --- a/holidays/locale/pt_AO/LC_MESSAGES/AO.po +++ b/holidays/locale/pt_AO/LC_MESSAGES/AO.po @@ -20,7 +20,7 @@ msgstr "" msgid "Dia de eleições gerais" msgstr "" -#. Day off for %s. +#. %s (Observed). #, c-format msgid "%s (Ponte)" msgstr "" diff --git a/holidays/locale/sr/LC_MESSAGES/BA.po b/holidays/locale/sr/LC_MESSAGES/BA.po index 9a35b07cd..025715739 100644 --- a/holidays/locale/sr/LC_MESSAGES/BA.po +++ b/holidays/locale/sr/LC_MESSAGES/BA.po @@ -16,6 +16,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.2.2\n" +#. %s (Observed). #, c-format msgid "%s (preneseno)" msgstr "%s (пренешено)" diff --git a/holidays/locale/sr/LC_MESSAGES/RS.po b/holidays/locale/sr/LC_MESSAGES/RS.po index 6a560a87e..803c5558c 100644 --- a/holidays/locale/sr/LC_MESSAGES/RS.po +++ b/holidays/locale/sr/LC_MESSAGES/RS.po @@ -51,6 +51,7 @@ msgstr "" msgid "Други дан Васкрса" msgstr "" +#. %s (Observed). #, c-format msgid "%s (слободан дан)" msgstr "" diff --git a/holidays/locale/th/LC_MESSAGES/CA.po b/holidays/locale/th/LC_MESSAGES/CA.po index 86165f0c3..d0bdfe823 100644 --- a/holidays/locale/th/LC_MESSAGES/CA.po +++ b/holidays/locale/th/LC_MESSAGES/CA.po @@ -3,21 +3,24 @@ # msgid "" msgstr "" -"Project-Id-Version: Python Holidays 0.25\n" +"Project-Id-Version: Python Holidays 0.32\n" "POT-Creation-Date: 2023-02-24 17:37+0700\n" -"PO-Revision-Date: 2023-02-24 17:37+0700\n" -"Last-Translator: PPsyrius \n" +"PO-Revision-Date: 2023-08-26 18:27+0300\n" +"Last-Translator: ~Jhellico \n" "Language-Team: Python Holidays localization team\n" "Language: th\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" "Generated-By: pygettext.py 1.5\n" +"X-Generator: Poedit 3.2.2\n" #. New Year's Day. msgid "New Year's Day" msgstr "วันขึ้นปีใหม่" +#. %s (Observed). #, c-format msgid "%s (Observed)" msgstr "ชดเชย%s" @@ -118,8 +121,8 @@ msgstr "พระราชพิธีพระบรมศพของสมเ msgid "National Day for Truth and Reconciliation" msgstr "วันชาติแห่งความจริงและการปรองดอง" -#. Thanksgiving. -msgid "Thanksgiving" +#. Thanksgiving Day. +msgid "Thanksgiving Day" msgstr "วันขอบคุณพระเจ้า" #. Remembrance Day. @@ -137,3 +140,11 @@ msgstr "วันเปิดกล่องของขวัญ" #. Terry Fox Day. msgid "Terry Fox Day" msgstr "วันเทร์รี ฟอกซ์" + +#. Orangemen's Day. +msgid "Orangemen's Day" +msgstr "วันออเรนจ์เมนส์" + +#. Natal Day. +msgid "Natal Day" +msgstr "วันสถาปนา" diff --git a/holidays/locale/th/LC_MESSAGES/TH.po b/holidays/locale/th/LC_MESSAGES/TH.po index 51912cf62..c7c0b7956 100644 --- a/holidays/locale/th/LC_MESSAGES/TH.po +++ b/holidays/locale/th/LC_MESSAGES/TH.po @@ -3,7 +3,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Python Holidays 0.24\n" +"Project-Id-Version: Python Holidays 0.33\n" "POT-Creation-Date: 2023-03-02 00:37+0700\n" "PO-Revision-Date: \n" "Last-Translator: PPsyrius \n" @@ -67,7 +67,7 @@ msgstr "" msgid "ชดเชยวันสงกรานต์" msgstr "" -#. %s (in lieu) +#. %s (in lieu). #, c-format msgid "ชดเชย%s" msgstr "" @@ -80,6 +80,10 @@ msgstr "" msgid "วันสิ้นปี" msgstr "" +#. National Children's Day +msgid "วันเด็กแห่งชาติ" +msgstr "" + #. Chakri Memorial Day. msgid "วันจักรี" msgstr "" @@ -100,6 +104,7 @@ msgstr "" msgid "วันฉัตรมงคล" msgstr "" +#. HM Queen Suthida's Birthday. msgid "" "วันเฉลิมพระชนมพรรษาสมเด็จพระนางเจ้าสุทิดา พัชรสุธาพิมลลักษณ พระบรมราชินี" msgstr "" @@ -176,6 +181,60 @@ msgstr "" msgid "วันเข้าพรรษา" msgstr "" +#. Royal Thai Armed Forces Day +msgid "วันกองทัพไทย" +msgstr "" + +#. Additional Closing Day for Bank for Agriculture and Agricultural +#. Cooperatives +msgid "" +"วันหยุดเพิ่มเติมสำหรับการปิดบัญชีประจำปีของธนาคารเพื่อการเกษตรและสหกรณ์การเกษตร" +msgstr "" + +#. Mid-Year Closing Day +msgid "วันหยุดภาคครึ่งปีของสถาบันการเงินและสถาบันการเงินเฉพาะกิจ" +msgstr "" + #. Royal Ploughing Ceremony. msgid "วันพืชมงคล" msgstr "" + +#. Teacher's Day +msgid "วันครู" +msgstr "" + +#. National Aviation Day +msgid "วันการบินแห่งชาติ" +msgstr "" + +#. National Forest Conservation Day +msgid "วันอนุรักษ์ทรัพยากรป่าไม้ของชาติ" +msgstr "" + +#. National Artist Day +msgid "วันศิลปินแห่งชาติ" +msgstr "" + +#. International Women's Day +msgid "วันสตรีสากล" +msgstr "" + +#. Loy Krathong +msgid "วันลอยกระทง" +msgstr "" + +#. Thai Veterans Day +msgid "วันทหารผ่านศึก" +msgstr "" + +#. National Science Day +msgid "วันวิทยาศาสตร์แห่งชาติ" +msgstr "" + +#. HM King Ramkamhaeng Memorial Day +msgid "วันพ่อขุนรามคำแหงมหาราช" +msgstr "" + +#. Thai National Flag Day +msgid "วันพระราชทานธงชาติไทย" +msgstr "" diff --git a/holidays/locale/uk/LC_MESSAGES/AO.po b/holidays/locale/uk/LC_MESSAGES/AO.po index 363a4f015..7f12f21dc 100644 --- a/holidays/locale/uk/LC_MESSAGES/AO.po +++ b/holidays/locale/uk/LC_MESSAGES/AO.po @@ -20,7 +20,7 @@ msgstr "" msgid "Dia de eleições gerais" msgstr "День загальних виборів" -#. Day off for %s. +#. %s (Observed). #, c-format msgid "%s (Ponte)" msgstr "Вихідний за %s" diff --git a/holidays/locale/uk/LC_MESSAGES/AR.po b/holidays/locale/uk/LC_MESSAGES/AR.po index 58d80c785..5aedd70ba 100644 --- a/holidays/locale/uk/LC_MESSAGES/AR.po +++ b/holidays/locale/uk/LC_MESSAGES/AR.po @@ -121,6 +121,7 @@ msgstr "День Колумба" msgid "Día de la Soberanía Nacional" msgstr "День національного суверенітету" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "%s (вихідний)" diff --git a/holidays/locale/uk/LC_MESSAGES/BA.po b/holidays/locale/uk/LC_MESSAGES/BA.po index b13d8138d..233f763eb 100644 --- a/holidays/locale/uk/LC_MESSAGES/BA.po +++ b/holidays/locale/uk/LC_MESSAGES/BA.po @@ -16,6 +16,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.2.2\n" +#. %s (Observed). #, c-format msgid "%s (preneseno)" msgstr "%s (вихідний)" diff --git a/holidays/locale/uk/LC_MESSAGES/BE.po b/holidays/locale/uk/LC_MESSAGES/BE.po index c623fe425..e0b5b01cd 100644 --- a/holidays/locale/uk/LC_MESSAGES/BE.po +++ b/holidays/locale/uk/LC_MESSAGES/BE.po @@ -3,9 +3,9 @@ # msgid "" msgstr "" -"Project-Id-Version: Python Holidays 0.28\n" +"Project-Id-Version: Python Holidays 0.33\n" "POT-Creation-Date: 2023-06-27 13:17+0300\n" -"PO-Revision-Date: 2023-06-27 14:11+0300\n" +"PO-Revision-Date: 2023-09-06 20:53+0300\n" "Last-Translator: ~Jhellico \n" "Language-Team: Python Holidays localization team\n" "Language: uk\n" @@ -33,7 +33,7 @@ msgid "Dag van de Arbeid" msgstr "День праці" #. Ascension Day. -msgid "Hemelvaart" +msgid "O. L. H. Hemelvaart" msgstr "Вознесіння Господнє" #. Whit Sunday. @@ -49,7 +49,7 @@ msgid "Nationale feestdag" msgstr "Національне свято" #. Assumption of Mary. -msgid "Onze Lieve Vrouw hemelvaart" +msgid "O. L. V. Hemelvaart" msgstr "Внебовзяття Пресвятої Діви Марії" #. All Saints' Day. @@ -63,3 +63,15 @@ msgstr "День перемирʼя" #. Christmas Day. msgid "Kerstmis" msgstr "Різдво Христове" + +#. Good Friday. +msgid "Goede Vrijdag" +msgstr "Страсна пʼятниця" + +#. Friday after Ascension Day. +msgid "Vrijdag na O. L. H. Hemelvaart" +msgstr "Пʼятниця після Вознесіння Господнього" + +#. Bank Holiday. +msgid "Banksluitingsdag" +msgstr "Банківський вихідний" diff --git a/holidays/locale/uk/LC_MESSAGES/BG.po b/holidays/locale/uk/LC_MESSAGES/BG.po index 35ce35832..b62ca5206 100644 --- a/holidays/locale/uk/LC_MESSAGES/BG.po +++ b/holidays/locale/uk/LC_MESSAGES/BG.po @@ -68,6 +68,7 @@ msgstr "Святий вечір" msgid "Рождество Христово" msgstr "Різдво Христове" +#. %s (Observed). #, c-format msgid "%s (почивен ден)" msgstr "%s (вихідний)" diff --git a/holidays/locale/uk/LC_MESSAGES/CO.po b/holidays/locale/uk/LC_MESSAGES/CO.po index ea2ec8337..49125527c 100644 --- a/holidays/locale/uk/LC_MESSAGES/CO.po +++ b/holidays/locale/uk/LC_MESSAGES/CO.po @@ -88,6 +88,7 @@ msgstr "Свято Тіла і Крові Христових" msgid "Sagrado Corazón" msgstr "Свято Найсвятішого Серця Ісуса" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "%s (вихідний)" diff --git a/holidays/locale/uk/LC_MESSAGES/CR.po b/holidays/locale/uk/LC_MESSAGES/CR.po index bbed989db..2582ff44e 100644 --- a/holidays/locale/uk/LC_MESSAGES/CR.po +++ b/holidays/locale/uk/LC_MESSAGES/CR.po @@ -16,6 +16,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.3\n" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "%s (вихідний)" diff --git a/holidays/locale/uk/LC_MESSAGES/CU.po b/holidays/locale/uk/LC_MESSAGES/CU.po index 4a6c0cd41..285692878 100644 --- a/holidays/locale/uk/LC_MESSAGES/CU.po +++ b/holidays/locale/uk/LC_MESSAGES/CU.po @@ -16,6 +16,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.2.2\n" +#. %s Observed. #, c-format msgid "%s (Observado)" msgstr "%s (вихідний)" diff --git a/holidays/locale/uk/LC_MESSAGES/EC.po b/holidays/locale/uk/LC_MESSAGES/EC.po index 9edbe5045..08845ae58 100644 --- a/holidays/locale/uk/LC_MESSAGES/EC.po +++ b/holidays/locale/uk/LC_MESSAGES/EC.po @@ -56,6 +56,7 @@ msgstr "День незалежності Куенки" msgid "Día de Navidad" msgstr "Різдво Христове" +#. %s (Observed). #, c-format msgid "%s (Observado)" msgstr "%s (вихідний)" diff --git a/holidays/locale/uk/LC_MESSAGES/LV.po b/holidays/locale/uk/LC_MESSAGES/LV.po index 8f981b231..624e6df21 100644 --- a/holidays/locale/uk/LC_MESSAGES/LV.po +++ b/holidays/locale/uk/LC_MESSAGES/LV.po @@ -32,6 +32,7 @@ msgid "" msgstr "" "День здобуття збірною Латвії з хокею бронзової медалі Чемпіонату світу" +#. %s (Observed). #, c-format msgid "%s (brīvdiena)" msgstr "%s (вихідний)" diff --git a/holidays/locale/uk/LC_MESSAGES/MC.po b/holidays/locale/uk/LC_MESSAGES/MC.po index c5a9b807f..95f876064 100644 --- a/holidays/locale/uk/LC_MESSAGES/MC.po +++ b/holidays/locale/uk/LC_MESSAGES/MC.po @@ -16,9 +16,11 @@ msgstr "" "Generated-By: Lingua 4.15.0\n" "X-Generator: Poedit 3.2.2\n" +#. Public holiday. msgid "Jour férié" msgstr "Державне свято" +#. %s (Observed). #, c-format msgid "%s (Observé)" msgstr "%s (вихідний)" diff --git a/holidays/locale/uk/LC_MESSAGES/UA.po b/holidays/locale/uk/LC_MESSAGES/UA.po index b917d21db..1e2bc4ae0 100644 --- a/holidays/locale/uk/LC_MESSAGES/UA.po +++ b/holidays/locale/uk/LC_MESSAGES/UA.po @@ -25,6 +25,7 @@ msgstr "" msgid "Вихідний день (перенесено з %s)" msgstr "" +#. %s (Observed). #, c-format msgid "%s (вихідний)" msgstr "" diff --git a/holidays/observed_holiday_base.py b/holidays/observed_holiday_base.py new file mode 100644 index 000000000..01b75ee74 --- /dev/null +++ b/holidays/observed_holiday_base.py @@ -0,0 +1,155 @@ +# python-holidays +# --------------- +# A fast, efficient Python library for generating country, province and state +# specific sets of holidays on the fly. It aims to make determining whether a +# specific date is a holiday as fast and flexible as possible. +# +# Authors: dr-prodigy (c) 2017-2022 +# ryanss (c) 2014-2017 +# Website: https://github.com/dr-prodigy/python-holidays +# License: MIT (see LICENSE file) + +from datetime import date +from datetime import timedelta as td +from typing import Dict, Optional, Tuple, Set + +from holidays.calendars.gregorian import MON, TUE, WED, THU, FRI, SAT, SUN +from holidays.holiday_base import DateArg, HolidayBase + + +class ObservedRule(Dict[int, int]): + __slots__ = () + + def __add__(self, other): + return ObservedRule({**self, **other}) + + +# Observance calculation rules: +7 - next workday, -7 - previous workday. +# Single days. +MON_TO_NEXT_TUE = ObservedRule({MON: +1}) + +TUE_TO_PREV_MON = ObservedRule({TUE: -1}) +TUE_TO_PREV_FRI = ObservedRule({TUE: -4}) + +WED_TO_PREV_MON = ObservedRule({WED: -2}) +WED_TO_NEXT_FRI = ObservedRule({WED: +2}) + +THU_TO_PREV_MON = ObservedRule({THU: -3}) +THU_TO_PREV_WED = ObservedRule({THU: -1}) +THU_TO_NEXT_MON = ObservedRule({THU: +4}) +THU_TO_NEXT_FRI = ObservedRule({THU: +1}) + +FRI_TO_PREV_THU = ObservedRule({FRI: -1}) +FRI_TO_NEXT_MON = ObservedRule({FRI: +3}) +FRI_TO_NEXT_SAT = ObservedRule({FRI: +1}) +FRI_TO_NEXT_WORKDAY = ObservedRule({FRI: +7}) + +SAT_TO_PREV_FRI = ObservedRule({SAT: -1}) +SAT_TO_PREV_WORKDAY = ObservedRule({SAT: -7}) +SAT_TO_NEXT_MON = ObservedRule({SAT: +2}) +SAT_TO_NEXT_TUE = ObservedRule({SAT: +3}) +SAT_TO_NEXT_SUN = ObservedRule({SAT: +1}) +SAT_TO_NEXT_WORKDAY = ObservedRule({SAT: +7}) + +SUN_TO_NEXT_MON = ObservedRule({SUN: +1}) +SUN_TO_NEXT_TUE = ObservedRule({SUN: +2}) +SUN_TO_NEXT_WED = ObservedRule({SUN: +3}) +SUN_TO_NEXT_WORKDAY = ObservedRule({SUN: +7}) + +# Multiple days. +ALL_TO_NEAREST_MON = ObservedRule({TUE: -1, WED: -2, THU: -3, FRI: +3, SAT: +2, SUN: +1}) +ALL_TO_NEAREST_MON_LATAM = ObservedRule({TUE: -1, WED: -2, THU: 4, FRI: +3, SAT: +2, SUN: +1}) +ALL_TO_NEXT_MON = ObservedRule({TUE: +6, WED: +5, THU: +4, FRI: +3, SAT: +2, SUN: +1}) +ALL_TO_NEXT_SUN = ObservedRule({MON: +6, TUE: +5, WED: +4, THU: +3, FRI: +2, SAT: +1}) + +WORKDAY_TO_NEAREST_MON = ObservedRule({TUE: -1, WED: -2, THU: -3, FRI: +3}) +WORKDAY_TO_NEXT_MON = ObservedRule({TUE: +6, WED: +5, THU: +4, FRI: +3}) +WORKDAY_TO_NEXT_WORKDAY = ObservedRule({MON: +7, TUE: +7, WED: +7, THU: +7, FRI: +7}) + +TUE_WED_TO_PREV_MON = ObservedRule({TUE: -1, WED: -2}) +TUE_WED_THU_TO_PREV_MON = ObservedRule({TUE: -1, WED: -2, THU: -3}) + +WED_THU_TO_NEXT_FRI = ObservedRule({WED: +2, THU: +1}) + +THU_FRI_TO_NEXT_MON = ObservedRule({THU: +4, FRI: +3}) +THU_FRI_TO_NEXT_WORKDAY = ObservedRule({THU: +7, FRI: +7}) +THU_FRI_SUN_TO_NEXT_MON = ObservedRule({THU: +4, FRI: +3, SUN: +1}) + +FRI_SAT_TO_NEXT_WORKDAY = ObservedRule({FRI: +7, SAT: +7}) +FRI_SUN_TO_NEXT_MON = ObservedRule({FRI: +3, SUN: +1}) +FRI_SUN_TO_NEXT_SAT_MON = ObservedRule({FRI: +1, SUN: +1}) + +SAT_SUN_TO_PREV_FRI = ObservedRule({SAT: -1, SUN: -2}) +SAT_SUN_TO_NEXT_MON = ObservedRule({SAT: +2, SUN: +1}) +SAT_SUN_TO_NEXT_TUE = ObservedRule({SAT: +3, SUN: +2}) +SAT_SUN_TO_NEXT_MON_TUE = ObservedRule({SAT: +2, SUN: +2}) +SAT_SUN_TO_NEXT_WORKDAY = ObservedRule({SAT: +7, SUN: +7}) + + +class ObservedHolidayBase(HolidayBase): + """Observed holidays implementation.""" + + observed_label = "%s" + + def __init__(self, observed_rule: ObservedRule, observed_since: int = None, *args, **kwargs): + self._observed_rule = observed_rule + self._observed_since = observed_since + + super().__init__(*args, **kwargs) + + def _is_observed(self, *args, **kwargs) -> bool: + return self._observed_since is None or self._year >= self._observed_since + + def _get_observed_date(self, dt: date, rule: ObservedRule) -> date: + delta = rule.get(dt.weekday(), 0) + if delta != 0: + if abs(delta) == 7: + delta //= 7 + dt += td(days=delta) + while dt.year == self._year and ( + dt in self or self._is_weekend(dt) # type: ignore[operator] + ): + dt += td(days=delta) + else: + dt += td(days=delta) + return dt + + def _add_observed( + self, dt: DateArg, name: Optional[str] = None, rule: Optional[ObservedRule] = None + ) -> Tuple[bool, date]: + dt = dt if isinstance(dt, date) else date(self._year, *dt) + + if not self.observed or not self._is_observed(dt): + return False, dt + + dt_observed = self._get_observed_date(dt, rule or self._observed_rule) + if dt_observed == dt: + return False, dt + + observed_label = getattr( + self, + "observed_label_before" if dt_observed < dt else "observed_label", + self.observed_label, + ) + for name in (name,) if name else self.get_list(dt): + super()._add_holiday(self.tr(observed_label) % self.tr(name), dt_observed) + return True, dt_observed + + def _move_holiday(self, dt: date, rule: Optional[ObservedRule] = None) -> Tuple[bool, date]: + is_observed, dt_observed = self._add_observed(dt, rule=rule) + if is_observed: + self.pop(dt) + return is_observed, dt_observed if is_observed else dt + + def _populate_observed(self, dts: Set[date], multiple: bool = False) -> None: + """ + When multiple is True, each holiday from a given date has its own observed date. + """ + for dt in sorted(dts): + if not self._is_observed(dt): + continue + if multiple: + for name in self.get_list(dt): + self._add_observed(dt, name) + else: + self._add_observed(dt) diff --git a/tests/common.py b/tests/common.py index b543e12bc..a61f2d403 100644 --- a/tests/common.py +++ b/tests/common.py @@ -10,6 +10,7 @@ # License: MIT (see LICENSE file) import os +import sys import unittest import warnings from datetime import date @@ -20,7 +21,8 @@ from holidays import HolidayBase from holidays.calendars.gregorian import SUN -PYTHON_VERSION = (3, 11) +PYTHON_LATEST_SUPPORTED_VERSION = (3, 11) +PYTHON_VERSION = (sys.version_info.major, sys.version_info.minor) class TestCase(unittest.TestCase): diff --git a/tests/countries/test_algeria.py b/tests/countries/test_algeria.py index fcdd3a556..1c9479097 100644 --- a/tests/countries/test_algeria.py +++ b/tests/countries/test_algeria.py @@ -150,3 +150,20 @@ def test_l10n_en_us(self): ("2022-10-08", "Prophet's Birthday* (*estimated)"), ("2022-11-01", "Revolution Day"), ) + + def test_l10n_fr(self): + self.assertLocalizedHolidays( + "fr", + ("2022-01-01", "Nouvel an"), + ("2022-01-12", "Nouvel an Amazigh"), + ("2022-05-01", "Fête du Travail"), + ("2022-05-02", "Fête de la rupture du jeûne* (*estimé)"), + ("2022-05-03", "Congé de fête de la rupture du jeûne* (*estimé)"), + ("2022-07-05", "Fête de l'indépendance"), + ("2022-07-09", "Fête du sacrifice* (*estimé)"), + ("2022-07-10", "Congé de fête du sacrifice* (*estimé)"), + ("2022-07-30", "Nouvel an musulman* (*estimé)"), + ("2022-08-08", "Achoura* (*estimé)"), + ("2022-10-08", "Anniversaire du prophète* (*estimé)"), + ("2022-11-01", "Fête de la Révolution"), + ) diff --git a/tests/countries/test_belgium.py b/tests/countries/test_belgium.py index d00b84de3..9f858a6a2 100644 --- a/tests/countries/test_belgium.py +++ b/tests/countries/test_belgium.py @@ -9,6 +9,7 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) +from holidays.constants import BANK from holidays.countries.belgium import Belgium, BE, BEL from tests.common import TestCase @@ -21,33 +22,17 @@ def setUpClass(cls): def test_country_aliases(self): self.assertCountryAliases(Belgium, BE, BEL) - def test_2019(self): - self.assertHolidays( - ("2019-01-01", "Nieuwjaar"), - ("2019-04-21", "Pasen"), - ("2019-04-22", "Paasmaandag"), - ("2019-05-01", "Dag van de Arbeid"), - ("2019-05-30", "Hemelvaart"), - ("2019-06-09", "Pinksteren"), - ("2019-06-10", "Pinkstermaandag"), - ("2019-07-21", "Nationale feestdag"), - ("2019-08-15", "Onze Lieve Vrouw hemelvaart"), - ("2019-11-01", "Allerheiligen"), - ("2019-11-11", "Wapenstilstand"), - ("2019-12-25", "Kerstmis"), - ) - def test_2020(self): self.assertHolidays( ("2020-01-01", "Nieuwjaar"), ("2020-04-12", "Pasen"), ("2020-04-13", "Paasmaandag"), ("2020-05-01", "Dag van de Arbeid"), - ("2020-05-21", "Hemelvaart"), + ("2020-05-21", "O. L. H. Hemelvaart"), ("2020-05-31", "Pinksteren"), ("2020-06-01", "Pinkstermaandag"), ("2020-07-21", "Nationale feestdag"), - ("2020-08-15", "Onze Lieve Vrouw hemelvaart"), + ("2020-08-15", "O. L. V. Hemelvaart"), ("2020-11-01", "Allerheiligen"), ("2020-11-11", "Wapenstilstand"), ("2020-12-25", "Kerstmis"), @@ -59,40 +44,69 @@ def test_2021(self): ("2021-04-04", "Pasen"), ("2021-04-05", "Paasmaandag"), ("2021-05-01", "Dag van de Arbeid"), - ("2021-05-13", "Hemelvaart"), + ("2021-05-13", "O. L. H. Hemelvaart"), ("2021-05-23", "Pinksteren"), ("2021-05-24", "Pinkstermaandag"), ("2021-07-21", "Nationale feestdag"), - ("2021-08-15", "Onze Lieve Vrouw hemelvaart"), + ("2021-08-15", "O. L. V. Hemelvaart"), ("2021-11-01", "Allerheiligen"), ("2021-11-11", "Wapenstilstand"), ("2021-12-25", "Kerstmis"), ) + def test_2022(self): + self.assertHolidays( + ("2022-01-01", "Nieuwjaar"), + ("2022-04-17", "Pasen"), + ("2022-04-18", "Paasmaandag"), + ("2022-05-01", "Dag van de Arbeid"), + ("2022-05-26", "O. L. H. Hemelvaart"), + ("2022-06-05", "Pinksteren"), + ("2022-06-06", "Pinkstermaandag"), + ("2022-07-21", "Nationale feestdag"), + ("2022-08-15", "O. L. V. Hemelvaart"), + ("2022-11-01", "Allerheiligen"), + ("2022-11-11", "Wapenstilstand"), + ("2022-12-25", "Kerstmis"), + ) + + def test_bank_2022(self): + self.assertHolidays( + Belgium(categories=(BANK,), years=2022), + ("2022-04-15", "Goede Vrijdag"), + ("2022-05-27", "Vrijdag na O. L. H. Hemelvaart"), + ("2022-12-26", "Banksluitingsdag"), + ) + def test_l10n_default(self): self.assertLocalizedHolidays( ("2022-01-01", "Nieuwjaar"), + ("2022-04-15", "Goede Vrijdag"), ("2022-04-17", "Pasen"), ("2022-04-18", "Paasmaandag"), ("2022-05-01", "Dag van de Arbeid"), - ("2022-05-26", "Hemelvaart"), + ("2022-05-26", "O. L. H. Hemelvaart"), + ("2022-05-27", "Vrijdag na O. L. H. Hemelvaart"), ("2022-06-05", "Pinksteren"), ("2022-06-06", "Pinkstermaandag"), ("2022-07-21", "Nationale feestdag"), - ("2022-08-15", "Onze Lieve Vrouw hemelvaart"), + ("2022-08-15", "O. L. V. Hemelvaart"), ("2022-11-01", "Allerheiligen"), ("2022-11-11", "Wapenstilstand"), ("2022-12-25", "Kerstmis"), + ("2022-12-26", "Banksluitingsdag"), ) def test_l10n_de(self): self.assertLocalizedHolidays( "de", ("2022-01-01", "Neujahr"), + ("2022-04-15", "Karfreitag"), ("2022-04-17", "Ostern"), ("2022-04-18", "Ostermontag"), ("2022-05-01", "Tag der Arbeit"), ("2022-05-26", "Christi Himmelfahrt"), + ("2022-05-27", "Freitag nach Christi Himmelfahrt"), ("2022-06-05", "Pfingsten"), ("2022-06-06", "Pfingstmontag"), ("2022-07-21", "Nationalfeiertag"), @@ -100,16 +114,19 @@ def test_l10n_de(self): ("2022-11-01", "Allerheiligen"), ("2022-11-11", "Waffenstillstand"), ("2022-12-25", "Weihnachten"), + ("2022-12-26", "Bankschlusstag"), ) def test_l10n_en_us(self): self.assertLocalizedHolidays( "en_US", ("2022-01-01", "New Year's Day"), + ("2022-04-15", "Good Friday"), ("2022-04-17", "Easter"), ("2022-04-18", "Easter Monday"), ("2022-05-01", "Labor Day"), ("2022-05-26", "Ascension Day"), + ("2022-05-27", "Friday after Ascension Day"), ("2022-06-05", "Whit Sunday"), ("2022-06-06", "Whit Monday"), ("2022-07-21", "National Day"), @@ -117,16 +134,19 @@ def test_l10n_en_us(self): ("2022-11-01", "All Saints' Day"), ("2022-11-11", "Armistice Day"), ("2022-12-25", "Christmas Day"), + ("2022-12-26", "Bank Holiday"), ) def test_l10n_fr(self): self.assertLocalizedHolidays( "fr", ("2022-01-01", "Nouvel An"), + ("2022-04-15", "Vendredi Saint"), ("2022-04-17", "Pâques"), ("2022-04-18", "Lundi de Pâques"), ("2022-05-01", "Fête du Travail"), ("2022-05-26", "Ascension"), + ("2022-05-27", "Vendredi suivant l'Ascension"), ("2022-06-05", "Pentecôte"), ("2022-06-06", "Lundi de Pentecôte"), ("2022-07-21", "Fête nationale"), @@ -134,16 +154,19 @@ def test_l10n_fr(self): ("2022-11-01", "Toussaint"), ("2022-11-11", "Jour de l'Armistice"), ("2022-12-25", "Noël"), + ("2022-12-26", "Jour de fermeture bancaire"), ) def test_l10n_uk(self): self.assertLocalizedHolidays( "uk", ("2022-01-01", "Новий рік"), + ("2022-04-15", "Страсна пʼятниця"), ("2022-04-17", "Великдень"), ("2022-04-18", "Великодній понеділок"), ("2022-05-01", "День праці"), ("2022-05-26", "Вознесіння Господнє"), + ("2022-05-27", "Пʼятниця після Вознесіння Господнього"), ("2022-06-05", "Трійця"), ("2022-06-06", "День Святого Духа"), ("2022-07-21", "Національне свято"), @@ -151,4 +174,5 @@ def test_l10n_uk(self): ("2022-11-01", "День усіх святих"), ("2022-11-11", "День перемирʼя"), ("2022-12-25", "Різдво Христове"), + ("2022-12-26", "Банківський вихідний"), ) diff --git a/tests/countries/test_brazil.py b/tests/countries/test_brazil.py index 7ac7e7625..3382e00f9 100644 --- a/tests/countries/test_brazil.py +++ b/tests/countries/test_brazil.py @@ -9,6 +9,7 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) +from holidays.constants import OPTIONAL, PUBLIC from holidays.countries.brazil import Brazil, BR, BRA from tests.common import TestCase @@ -22,7 +23,7 @@ def test_country_aliases(self): self.assertCountryAliases(Brazil, BR, BRA) def test_no_holidays(self): - self.assertNoHolidays(Brazil(years=1889)) + self.assertNoHolidays(Brazil(categories=(OPTIONAL, PUBLIC), years=1889)) def test_new_years_day(self): self.assertHoliday(f"{year}-01-01" for year in range(1890, 2050)) @@ -89,8 +90,8 @@ def test_christmas_day(self): self.assertNoHolidayName("Natal", range(1890, 1922)) def test_optional_holidays(self): - self.assertHolidayName( - "Carnaval", + holidays = Brazil(categories=(OPTIONAL,)) + dt = ( "2018-02-12", "2018-02-13", "2019-03-04", @@ -102,28 +103,32 @@ def test_optional_holidays(self): "2022-02-28", "2022-03-01", ) + self.assertHolidayName("Carnaval", holidays, dt) + self.assertNoHoliday(dt) - self.assertHolidayName( - "Início da Quaresma", + dt = ( "2018-02-14", "2019-03-06", "2020-02-26", "2021-02-17", "2022-03-02", ) + self.assertHolidayName("Início da Quaresma", holidays, dt) + self.assertNoHoliday(dt) - self.assertHolidayName( - "Corpus Christi", + dt = ( "2018-05-31", "2019-06-20", "2020-06-11", "2021-06-03", "2022-06-16", ) + self.assertHolidayName("Corpus Christi", holidays, dt) + self.assertNoHoliday(dt) - self.assertHoliday(f"{year}-10-28" for year in range(1950, 2050)) - self.assertHoliday(f"{year}-12-24" for year in range(1950, 2050)) - self.assertHoliday(f"{year}-12-31" for year in range(1950, 2050)) + for year in range(1950, 2050): + self.assertHoliday(holidays, f"{year}-10-28", f"{year}-12-24", f"{year}-12-31") + self.assertNoHoliday(f"{year}-10-28", f"{year}-12-24", f"{year}-12-31") def test_AC_holidays(self): ac_holidays = Brazil(subdiv="AC", years=range(1995, 2030)) diff --git a/tests/countries/test_bulgaria.py b/tests/countries/test_bulgaria.py index 495076b3b..e6f6e5806 100644 --- a/tests/countries/test_bulgaria.py +++ b/tests/countries/test_bulgaria.py @@ -10,7 +10,7 @@ # License: MIT (see LICENSE file) -from holidays.constants import SCHOOL +from holidays.constants import PUBLIC, SCHOOL from holidays.countries.bulgaria import Bulgaria, BG, BLG from tests.common import TestCase @@ -24,7 +24,7 @@ def test_country_aliases(self): self.assertCountryAliases(Bulgaria, BG, BLG) def test_no_holidays(self): - self.assertNoHolidays(Bulgaria(years=1989)) + self.assertNoHolidays(Bulgaria(categories=(PUBLIC, SCHOOL), years=1989)) def test_new_years_day(self): name = "Нова година" diff --git a/tests/countries/test_canada.py b/tests/countries/test_canada.py index 226f929f1..079abc9e5 100644 --- a/tests/countries/test_canada.py +++ b/tests/countries/test_canada.py @@ -9,6 +9,7 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) +from holidays.constants import GOVERNMENT, OPTIONAL from holidays.countries.canada import Canada, CA, CAN from tests.common import TestCase @@ -16,118 +17,49 @@ class TestCanada(TestCase): @classmethod def setUpClass(cls): - years = range(1900, 2050) - super().setUpClass(Canada, years=years) + years = range(1867, 2050) + super().setUpClass(Canada, years=years, years_non_observed=(range(2000, 2024))) cls.prov_hols = {prov: CA(subdiv=prov, years=years) for prov in CA.subdivisions} + cls.gov_hols = CA(years=years, categories=(GOVERNMENT,)) + cls.prov_opt_hols = { + prov: CA(subdiv=prov, years=years, categories=(OPTIONAL,)) for prov in CA.subdivisions + } def test_country_aliases(self): self.assertCountryAliases(Canada, CA, CAN) def test_no_holidays(self): self.assertNoHolidays(Canada(years=1866)) + self.assertNoHolidays(Canada(years=1866, categories=(GOVERNMENT,))) + self.assertNoHolidays(Canada(years=1866, categories=(OPTIONAL,))) - def test_new_years(self): - self.assertHoliday(f"{year}-01-01" for year in range(1900, 2050)) - self.assertHoliday("2011-01-03", "2017-01-02") - self.assertNoNonObservedHoliday("2011-01-03", "2017-01-02") - - def test_islander_day(self): - dt = ( - "2010-02-15", - "2011-02-21", - "2012-02-20", - "2013-02-18", - "2014-02-17", - "2015-02-16", - "2016-02-15", - "2020-02-17", - ) - self.assertHoliday(self.prov_hols["PE"], dt, "2009-02-09") - for d in dt: - self.assertNotEqual(self.holidays[d], "Islander Day") - - def test_yukon_heritage_day(self): - # https://www.timeanddate.com/holidays/canada/heritage-day-yukon - dt = ( - "2017-02-24", - "2018-02-23", - "2019-02-22", - "2020-02-21", - "2021-02-26", - "2022-02-25", - ) - self.assertHoliday(self.prov_hols["YT"], dt) - - def test_family_day(self): - ab_holidays = self.prov_hols["AB"] - bc_holidays = self.prov_hols["BC"] - mb_holidays = self.prov_hols["MB"] - sk_holidays = self.prov_hols["SK"] - nb_holidays = self.prov_hols["NB"] - ns_holidays = self.prov_hols["NS"] - dt = ( - "1990-02-19", - "1999-02-15", - "2000-02-21", - "2006-02-20", + def test_new_years_day(self): + name = "New Year's Day" + name_observed = f"{name} (Observed)" + self.assertHolidayName(name, (f"{year}-01-01" for year in range(1867, 2050))) + self.assertHolidayName( + name, self.gov_hols, (f"{year}-01-01" for year in range(1867, 2050)) ) - self.assertNoHoliday(dt) - self.assertHoliday(ab_holidays, dt) - self.assertNoHoliday(bc_holidays, dt) - self.assertNoHoliday(mb_holidays, dt) - self.assertNoHoliday(sk_holidays, dt) - d = "2007-02-19" - self.assertNoHoliday(d) - self.assertHoliday(ab_holidays, d) - self.assertNoHoliday(bc_holidays, d) - self.assertNoHoliday(mb_holidays, d) - self.assertHoliday(sk_holidays, d) - dt = ( - "2008-02-18", - "2012-02-20", - "2014-02-17", - "2018-02-19", + for _, holidays in self.prov_hols.items(): + self.assertHolidayName(name, holidays, (f"{year}-01-01" for year in range(1867, 2050))) + + dts = ( + "2011-01-03", + "2012-01-02", + "2017-01-02", + "2022-01-03", + "2023-01-02", ) - self.assertHoliday(dt) - self.assertHoliday(ab_holidays, dt) - self.assertNoHoliday(bc_holidays, dt) - self.assertHoliday(mb_holidays, dt) - self.assertHoliday(sk_holidays, dt) - self.assertHoliday(nb_holidays, "2018-02-19") - dt = ("2019-02-18", "2020-02-17") - self.assertHoliday(dt) - self.assertHoliday(ab_holidays, dt) - self.assertHoliday(bc_holidays, dt) - self.assertHoliday(mb_holidays, dt) - self.assertHoliday(sk_holidays, dt) - dt = ("2013-02-11", "2016-02-08") - self.assertNoHoliday(dt) - self.assertNoHoliday(ab_holidays, dt) - self.assertHoliday(bc_holidays, dt) - self.assertNoHoliday(mb_holidays, dt) - self.assertNoHoliday(sk_holidays, dt) - self.assertHolidayName("Louis Riel Day", mb_holidays, "2014-02-17") - self.assertHolidayName("Heritage Day", ns_holidays, "2015-02-16") - - def test_st_patricks_day(self): - nl_holidays = self.prov_hols["NL"] - dt = ( - "1900-03-19", - "1999-03-15", - "2000-03-20", - "2012-03-19", - "2013-03-18", - "2014-03-17", - "2015-03-16", - "2016-03-14", - "2020-03-16", - ) - self.assertNoHoliday(dt) - self.assertHoliday(nl_holidays, dt) - self.assertNoHoliday(nl_holidays, "1899-03-20") + self.assertHolidayName(name_observed, dts) + self.assertHolidayName(name_observed, self.gov_hols, dts) + for prov, holidays in self.prov_hols.items(): + self.assertHolidayName(name_observed, holidays, dts) + self.assertNoNonObservedHoliday(CA(subdiv=prov, observed=False), dts) + self.assertNoNonObservedHoliday(dts) def test_good_friday(self): - self.assertHoliday( + name = "Good Friday" + dts = ( "1900-04-13", "1901-04-05", "1902-03-28", @@ -137,118 +69,436 @@ def test_good_friday(self): "2018-03-30", "2019-04-19", "2020-04-10", + "2021-04-02", + "2022-04-15", + "2023-04-07", ) + self.assertHolidayName(name, dts) + self.assertHolidayName(name, range(1867, 2050)) + self.assertHolidayName(name, self.gov_hols, dts) + self.assertHolidayName(name, self.gov_hols, range(1867, 2050)) + for _, holidays in self.prov_hols.items(): + self.assertHolidayName(name, holidays, dts) + self.assertHolidayName(name, holidays, range(1867, 2050)) - def test_easter_monday(self): - self.assertHoliday( - "1900-04-16", - "1901-04-08", - "1902-03-31", - "1999-04-05", - "2000-04-24", - "2010-04-05", - "2018-04-02", - "2019-04-22", - "2020-04-13", + def test_canada_day(self): + name_1 = "Dominion Day" + name_2 = "Canada Day" + self.assertHolidayName(name_1, (f"{year}-07-01" for year in range(1879, 1983))) + self.assertHolidayName(name_2, (f"{year}-07-01" for year in range(1983, 2050))) + self.assertNoHolidayName(name_1, range(1867, 1879), range(1983, 2050)) + self.assertNoHolidayName(name_2, range(1867, 1983)) + self.assertNoHoliday(f"{year}-07-01" for year in range(1867, 1879)) + + dts_sat = ( + "2000-07-03", + "2006-07-03", + "2017-07-03", + "2023-07-03", + ) + dts_sun = ( + "2001-07-02", + "2007-07-02", + "2012-07-02", + "2018-07-02", + ) + name_observed = f"{name_2} (Observed)" + self.assertNoHoliday(dts_sat, dts_sun) + self.assertHolidayName(name_observed, self.gov_hols, dts_sat, dts_sun) + self.assertNoNonObservedHoliday( + CA(observed=False, categories=(GOVERNMENT,)), dts_sat, dts_sun + ) + for prov, holidays in self.prov_hols.items(): + if prov in {"AB", "BC", "QC"}: + self.assertHolidayName(name_observed, self.prov_hols[prov], dts_sun) + self.assertNoHoliday(self.prov_hols[prov], dts_sat) + elif prov in {"NL", "PE", "SK", "YT"}: + self.assertHoliday(self.prov_hols[prov], dts_sat, dts_sun) + else: + self.assertNoHoliday(self.prov_hols[prov], dts_sat, dts_sun) + self.assertNoNonObservedHoliday(CA(subdiv=prov, observed=False), dts_sat, dts_sun) + + def test_labour_day(self): + name = "Labour Day" + self.assertNoHolidayName(name, range(1867, 1894)) + self.assertHolidayName(name, range(1894, 2050)) + self.assertNoHolidayName(name, self.gov_hols, range(1867, 1894)) + self.assertHolidayName(name, self.gov_hols, range(1894, 2050)) + + dts = ( + "1894-09-03", + "1900-09-03", + "1999-09-06", + "2000-09-04", + "2014-09-01", + "2015-09-07", + "2018-09-03", + "2019-09-02", + "2020-09-07", + "2021-09-06", + "2022-09-05", + "2023-09-04", ) + self.assertHolidayName(name, dts) + self.assertHolidayName(name, self.gov_hols, dts) + for _, holidays in self.prov_hols.items(): + self.assertHolidayName(name, holidays, dts) + self.assertHolidayName(name, holidays, range(1894, 2050)) + self.assertNoHolidayName(name, holidays, range(1867, 1894)) - def test_st_georges_day(self): - dt = ( - "1990-04-23", - "1999-04-26", - "2010-04-19", - "2016-04-25", - "2020-04-20", + def test_christmas_day(self): + name = "Christmas Day" + name_observed = f"{name} (Observed)" + self.assertHolidayName(name, (f"{year}-12-25" for year in range(1867, 2050))) + for _, holidays in self.prov_hols.items(): + self.assertHolidayName(name, holidays, (f"{year}-12-25" for year in range(1867, 2050))) + + dts_sat = ( + "2004-12-27", + "2010-12-27", + "2021-12-27", + ) + dts_sun_without_boxing = ( + "2005-12-26", + "2011-12-26", + "2016-12-26", + "2022-12-26", + ) + dts_sun_with_boxing = ( + "2005-12-27", + "2011-12-27", + "2016-12-27", + "2022-12-27", + ) + self.assertHolidayName(name_observed, dts_sat, dts_sun_without_boxing) + self.assertNoHoliday(dts_sun_with_boxing) + self.assertNoNonObservedHoliday(dts_sat, dts_sun_with_boxing, dts_sun_without_boxing) + self.assertHolidayName(name_observed, self.gov_hols, dts_sat, dts_sun_with_boxing) + self.assertNoNonObservedHoliday( + CA(observed=False, categories=(GOVERNMENT,)), + dts_sat, + dts_sun_with_boxing, + ) + self.assertHolidayName( + name_observed, CA(categories=(OPTIONAL,)), dts_sat, dts_sun_with_boxing + ) + self.assertNoNonObservedHoliday( + CA(observed=False, categories=(OPTIONAL,)), + dts_sat, + dts_sun_with_boxing, ) - self.assertNoHoliday(dt) - self.assertHoliday(self.prov_hols["NL"], dt) + for prov, holidays in self.prov_hols.items(): + self.assertHolidayName(name_observed, holidays, dts_sat, dts_sun_without_boxing) + self.assertNoHoliday(holidays, dts_sun_with_boxing) + self.assertNoNonObservedHoliday( + CA(subdiv=prov, observed=False), + dts_sat, + dts_sun_with_boxing, + ) def test_victoria_day(self): - dt = ("1953-05-18", "1999-05-24", "2000-05-22") - self.assertHoliday(dt) + name = "Victoria Day" + dts = ( + "1953-05-18", + "2000-05-22", + "2010-05-24", + "2018-05-21", + "2019-05-20", + "2020-05-18", + "2021-05-24", + "2022-05-23", + "2023-05-22", + ) + self.assertNoHolidayName(name) + self.assertHolidayName(name, self.gov_hols, dts) + self.assertHolidayName(name, self.gov_hols, range(1953, 2050)) + self.assertNoHolidayName(name, self.gov_hols, range(1867, 1953)) + for prov, holidays in self.prov_hols.items(): - if prov in {"NL", "NS", "PE", "QC"}: - self.assertNoHoliday(holidays, dt) + if prov in {"AB", "BC", "MB", "NT", "NU", "ON", "SK", "YT"}: + self.assertHolidayName(name, holidays, dts) + self.assertHolidayName(name, holidays, range(1953, 2050)) + self.assertNoHolidayName(name, holidays, range(1867, 1953)) else: - self.assertHoliday(holidays, dt) + self.assertNoHolidayName(name, holidays) + + def test_national_day_for_truth_and_reconciliation(self): + name = "National Day for Truth and Reconciliation" + name_observed = f"{name} (Observed)" + self.assertNoHolidayName(name) + self.assertHolidayName( + name, self.gov_hols, (f"{year}-09-30" for year in range(2021, 2050)) + ) + self.assertNoHolidayName(name, self.gov_hols, range(1867, 2021)) - dt = ("2010-05-24", "2015-05-18", "2020-05-18") - self.assertHoliday(dt) + dts = ( + "2023-10-02", + "2028-10-02", + "2029-10-01", + ) + self.assertHolidayName(name_observed, self.gov_hols, dts) + self.assertNoNonObservedHoliday(CA(observed=False, categories=(GOVERNMENT,)), dts) + + start_years = { + "AB": 2021, + "BC": 2023, + "NT": 2022, + "NU": 2022, + "PE": 2022, + "YT": 2023, + } for prov, holidays in self.prov_hols.items(): - if prov in {"NL", "NS", "PE"}: - self.assertNoHoliday(holidays, dt) + if prov in {"BC", "NT", "NU", "PE", "YT"}: + self.assertHolidayName( + name, holidays, (f"{year}-09-30" for year in range(start_years[prov], 2050)) + ) + self.assertNoHolidayName(name, holidays, range(1867, start_years[prov])) else: - self.assertHoliday(holidays, dt) + self.assertNoHolidayName(name, holidays) + self.assertNoNonObservedHoliday(CA(subdiv=prov, observed=False), dts) - def test_national_patriots_day(self): self.assertHolidayName( - "National Patriots' Day", - self.prov_hols["QC"], - "2010-05-24", - "2015-05-18", - "2020-05-18", - "2021-05-24", - "2022-05-23", + name, + CA(subdiv="AB", categories=(OPTIONAL,)), + (f"{year}-09-30" for year in range(2021, 2050)), ) - def test_national_aboriginal_day(self): - nt_holidays = self.prov_hols["NT"] - self.assertNoHoliday(nt_holidays, "1995-06-21") - self.assertNoHoliday(f"{year}-06-21" for year in range(1996, 2050)) - self.assertHoliday(nt_holidays, (f"{year}-06-21" for year in range(1996, 2050))) + def test_thanksgiving_day(self): + name = "Thanksgiving Day" + self.assertNoHolidayName(name) + self.assertHolidayName(name, self.gov_hols, range(1931, 2050)) + self.assertNoHolidayName(name, self.gov_hols, range(1867, 1931)) - def test_st_jean_baptiste_day(self): - qc_holidays = self.prov_hols["QC"] - self.assertNoHoliday(qc_holidays, "1924-06-24") - self.assertNoHoliday(f"{year}-06-24" for year in range(1925, 2050)) - self.assertHoliday(qc_holidays, (f"{year}-06-24" for year in range(1925, 2050))) - self.assertHoliday(qc_holidays, "2001-06-25") - self.assertNoNonObservedHoliday(Canada(subdiv="QC", observed=False), "2001-06-25") + dts = ( + "1931-10-12", + "1935-10-25", + "1990-10-08", + "1999-10-11", + "2000-10-09", + "2013-10-14", + "2018-10-08", + "2019-10-14", + "2020-10-12", + "2021-10-11", + "2022-10-10", + "2023-10-09", + ) + self.assertHolidayName(name, self.gov_hols, dts) + for prov, holidays in self.prov_hols.items(): + if prov in {"AB", "BC", "MB", "NT", "NU", "ON", "QC", "SK", "YT"}: + self.assertHolidayName(name, holidays, dts) + self.assertHolidayName(name, holidays, range(1931, 2050)) + self.assertNoHolidayName(name, holidays, range(1867, 1931)) + else: + self.assertNoHolidayName(name, holidays, dts) - def test_discovery_day(self): - nl_holidays = self.prov_hols["NL"] - yt_holidays = self.prov_hols["YT"] - dt = ( - "1997-06-23", - "1999-06-21", - "2000-06-26", - "2010-06-21", - "2016-06-27", - "2020-06-22", + for prov in ("NB", "NL"): + self.assertHolidayName(name, CA(subdiv=prov, categories=(OPTIONAL,)), dts) + + def test_remembrance_day(self): + name = "Remembrance Day" + name_observed = f"{name} (Observed)" + self.assertNoHolidayName(name) + self.assertHolidayName( + name, self.gov_hols, (f"{year}-11-11" for year in range(1931, 2050)) + ) + self.assertNoHoliday(self.gov_hols, (f"{year}-11-11" for year in range(1900, 1931))) + self.assertNoHolidayName(name, self.gov_hols, range(1900, 1931)) + + dts = ( + "2006-11-13", + "2007-11-12", + "2012-11-12", + "2017-11-13", + "2018-11-12", + "2023-11-13", ) - self.assertNoHoliday(dt) - self.assertHoliday(nl_holidays, dt) - self.assertNoHoliday(yt_holidays, dt) + self.assertHolidayName(name_observed, self.gov_hols, dts) + self.assertNoNonObservedHoliday(CA(observed=False, categories=(GOVERNMENT,)), dts) - dt = ( - "1912-08-19", - "1999-08-16", - "2000-08-21", - "2006-08-21", - "2016-08-15", - "2020-08-17", + for prov, holidays in self.prov_hols.items(): + if prov in {"AB", "BC", "NB", "NL", "NS", "NT", "NU", "PE", "SK", "YT"}: + start_year = 1981 if prov == "NS" else 1931 + self.assertHolidayName( + name, holidays, (f"{year}-11-11" for year in range(start_year, 2050)) + ) + self.assertNoHoliday( + holidays, (f"{year}-11-11" for year in range(1900, start_year)) + ) + self.assertNoHolidayName(name, holidays, range(1900, start_year)) + else: + self.assertNoHolidayName(name, holidays) + + if prov in {"AB", "NL", "NS", "PE", "SK", "YT"}: + self.assertHolidayName(name_observed, self.prov_hols[prov], dts) + self.assertNoNonObservedHoliday(CA(subdiv=prov, observed=False), dts) + else: + self.assertNoHoliday(holidays, dts) + + self.assertHolidayName( + name, + CA(subdiv="MB", categories=(OPTIONAL,)), + (f"{year}-11-11" for year in range(1931, 2050)), ) - self.assertNoHoliday(dt) - self.assertNoHoliday(nl_holidays, dt) - self.assertHoliday(yt_holidays, dt) - def test_canada_day(self): - self.assertHoliday(f"{year}-07-01" for year in range(1900, 2050)) - self.assertHoliday("2006-07-03", "2007-07-02") - self.assertNoNonObservedHoliday("2006-07-03", "2007-07-02") + def test_boxing_day(self): + name = "Boxing Day" + name_observed = f"{name} (Observed)" + self.assertNoHolidayName(name) + self.assertHolidayName( + name, self.gov_hols, (f"{year}-12-26" for year in range(1867, 2050)) + ) - def test_nunavut_day(self): - nu_holidays = self.prov_hols["NU"] - self.assertNoHoliday(nu_holidays, "1999-07-09", "2000-07-09") - self.assertHoliday(nu_holidays, "2000-04-01") - self.assertNoHoliday(f"{year}-07-09" for year in range(2001, 2050)) - self.assertHoliday(nu_holidays, (f"{year}-07-09" for year in range(2001, 2050))) - self.assertHoliday(nu_holidays, "2017-07-10") - self.assertNoNonObservedHoliday(Canada(subdiv="NU", observed=False), "2017-07-10") + opt_holidays = CA(years=range(1867, 2050), categories=(OPTIONAL,)) + self.assertHolidayName(name, opt_holidays, (f"{year}-12-26" for year in range(1867, 2050))) + + dts = ( + "2004-12-28", + "2009-12-28", + "2010-12-28", + "2015-12-28", + "2020-12-28", + "2021-12-28", + ) + self.assertHolidayName(name_observed, opt_holidays, dts) + self.assertNoNonObservedHoliday(CA(observed=False, categories=(OPTIONAL,)), dts) + + dts = ( + "2004-12-28", + "2010-12-28", + "2021-12-28", + ) + self.assertHolidayName(name_observed, self.prov_hols["ON"], dts) + self.assertNoNonObservedHoliday(CA(subdiv="ON", observed=False), dts) + + for prov in ("AB", "NB", "NL"): + self.assertHolidayName( + name, + CA(subdiv=prov, categories=(OPTIONAL,)), + (f"{year}-12-26" for year in range(1867, 2050)), + ) + + def test_family_day(self): + start_years = { + "AB": 1990, + "BC": 2019, + "MB": 2008, + "NB": 2018, + "NS": 2015, + "ON": 2008, + "PE": 2010, + "SK": 2007, + } + dts = ( + "1990-02-19", + "1991-02-18", + "1992-02-17", + "1993-02-15", + "1994-02-21", + "1995-02-20", + "1996-02-19", + "1997-02-17", + "1998-02-16", + "1999-02-15", + "2000-02-21", + "2001-02-19", + "2002-02-18", + "2003-02-17", + "2004-02-16", + "2005-02-21", + "2006-02-20", + "2007-02-19", + "2008-02-18", + "2009-02-16", + "2010-02-15", + "2011-02-21", + "2012-02-20", + "2013-02-18", + "2014-02-17", + "2015-02-16", + "2016-02-15", + "2017-02-20", + "2018-02-19", + "2019-02-18", + "2020-02-17", + "2021-02-15", + "2022-02-21", + "2023-02-20", + ) + prov_names = { + "MB": "Louis Riel Day", + "NS": "Heritage Day", + "PE": "Islander Day", + } + for prov, holidays in self.prov_hols.items(): + name = prov_names.get(prov, "Family Day") + for year, dt in enumerate(dts, 1990): + if prov in start_years and year >= start_years[prov]: + self.assertHolidayName(name, holidays, dt) + else: + self.assertNoHoliday(holidays, dt) + self.assertNoHoliday(dts) + self.assertNoHolidayName("Family Day") + for name in prov_names.values(): + self.assertNoHolidayName(name) + + self.assertHoliday( + self.prov_hols["BC"], + "2013-02-11", + "2014-02-10", + "2015-02-09", + "2016-02-08", + "2017-02-13", + "2018-02-12", + ) + self.assertHoliday(self.prov_hols["PE"], "2009-02-09") + + def test_easter_monday(self): + name = "Easter Monday" + dts = ( + "1900-04-16", + "1901-04-08", + "1902-03-31", + "1999-04-05", + "2000-04-24", + "2010-04-05", + "2018-04-02", + "2019-04-22", + "2020-04-13", + ) + self.assertNoHoliday(dts) + self.assertNoHolidayName(name) + self.assertNoHoliday(self.gov_hols, dts) + self.assertNoHolidayName(name, self.gov_hols) + + for prov, holidays in self.prov_hols.items(): + self.assertNoHoliday(holidays, dts) + self.assertNoHolidayName(name, holidays) + + if prov in {"AB", "QC"}: + self.assertHolidayName(name, CA(subdiv=prov, categories=(OPTIONAL,)), dts) + + def test_civic_holiday_ab(self): + name = "Heritage Day" + self.assertNoHolidayName(name, self.prov_hols["AB"]) + ab_opt_holidays = CA(subdiv="AB", categories=(OPTIONAL,)) + dts = ( + "1974-08-05", + "1999-08-02", + "2000-08-07", + "2010-08-02", + "2015-08-03", + "2020-08-03", + ) + self.assertNoHoliday(dts) + self.assertNoHolidayName(name) + self.assertHoliday(ab_opt_holidays, dts) + self.assertNoHoliday(ab_opt_holidays, "1973-08-06") def test_civic_holiday_bc(self): + name = "British Columbia Day" bc_holidays = self.prov_hols["BC"] - dt = ( + dts = ( "1974-08-05", "1999-08-02", "2000-08-07", @@ -256,12 +506,19 @@ def test_civic_holiday_bc(self): "2015-08-03", "2020-08-03", ) - self.assertHoliday(bc_holidays, dt) + self.assertNoHoliday(dts) + self.assertNoHolidayName(name) + self.assertHolidayName(name, bc_holidays, dts) self.assertNoHoliday(bc_holidays, "1973-08-06") def test_civic_holiday_mb(self): - mb_holidays = self.prov_hols["MB"] - dt = ( + old_name = "Civic Holiday" + new_name = "Terry Fox Day" + self.assertNoHolidayName(old_name, self.prov_hols["MB"]) + self.assertNoHolidayName(new_name, self.prov_hols["MB"]) + + mb_opt_holidays = CA(subdiv="MB", categories=(OPTIONAL,)) + dts = ( "1900-08-06", "1999-08-02", "2000-08-07", @@ -269,20 +526,57 @@ def test_civic_holiday_mb(self): "2015-08-03", "2020-08-03", ) - self.assertHoliday(mb_holidays, dt) - self.assertNoHoliday(mb_holidays, "1899-08-07") - old_name = "Civic Holiday" - new_name = "Terry Fox Day" - self.assertHolidayName(old_name, mb_holidays, "2014-08-04") - self.assertHolidayName(new_name, mb_holidays, "2015-08-03") - self.assertNoHolidayName(old_name, mb_holidays, 2015) - self.assertNoHolidayName(new_name, mb_holidays, 2014) - - def test_civic_holiday_nb_nt_sk(self): + self.assertNoHoliday(dts) + self.assertNoHolidayName(old_name) + self.assertNoHolidayName(new_name) + self.assertHoliday(mb_opt_holidays, dts) + self.assertNoHoliday(mb_opt_holidays, "1899-08-07") + self.assertHolidayName(old_name, mb_opt_holidays, "2014-08-04") + self.assertHolidayName(new_name, mb_opt_holidays, "2015-08-03") + self.assertNoHolidayName(old_name, mb_opt_holidays, 2015) + self.assertNoHolidayName(new_name, mb_opt_holidays, 2014) + + def test_civic_holiday_nb(self): + name = "New Brunswick Day" nb_holidays = self.prov_hols["NB"] + dts = ( + "1975-08-04", + "1999-08-02", + "2000-08-07", + "2010-08-02", + "2015-08-03", + "2020-08-03", + ) + self.assertNoHoliday(dts) + self.assertNoHolidayName(name) + self.assertHolidayName(name, nb_holidays, dts) + self.assertNoHoliday(nb_holidays, "1974-08-05") + self.assertNoHolidayName(name, nb_holidays, range(1867, 1975)) + + def test_civic_holiday_ns(self): + name = "Natal Day" + self.assertNoHolidayName(name, self.prov_hols["NS"]) + ns_opt_holidays = CA(subdiv="NS", categories=(OPTIONAL,)) + dts = ( + "1996-08-05", + "1999-08-02", + "2000-08-07", + "2010-08-02", + "2015-08-03", + "2020-08-03", + ) + self.assertNoHoliday(dts) + self.assertNoHolidayName(name) + self.assertHoliday(ns_opt_holidays, dts) + self.assertNoHoliday(ns_opt_holidays, "1995-08-07") + + def test_civic_holiday_nt_nu_on_sk(self): + name = "Civic Holiday" nt_holidays = self.prov_hols["NT"] + nu_holidays = self.prov_hols["NU"] + on_opt_holidays = CA(subdiv="ON", categories=(OPTIONAL,)) sk_holidays = self.prov_hols["SK"] - dt = ( + dts = ( "1900-08-06", "1999-08-02", "2000-08-07", @@ -290,92 +584,170 @@ def test_civic_holiday_nb_nt_sk(self): "2015-08-03", "2020-08-03", ) - self.assertHoliday(nb_holidays, dt) - self.assertHoliday(nt_holidays, dt) - self.assertHoliday(sk_holidays, dt) - self.assertNoHoliday(nb_holidays, "1899-08-07") + self.assertNoHoliday(dts) + self.assertNoHolidayName(name) + self.assertHolidayName(name, nt_holidays, dts) + self.assertHolidayName(name, nu_holidays, dts) + self.assertHolidayName(name, on_opt_holidays, dts) + self.assertHolidayName("Saskatchewan Day", sk_holidays, dts) self.assertNoHoliday(nt_holidays, "1899-08-07") + self.assertNoHoliday(nu_holidays, "1899-08-07") + self.assertNoHoliday(on_opt_holidays, "1899-08-07") self.assertNoHoliday(sk_holidays, "1899-08-07") - def test_labour_day(self): - self.assertNoHoliday("1893-09-04") - self.assertHoliday( - "1894-09-03", - "1900-09-03", - "1999-09-06", - "2000-09-04", - "2014-09-01", - "2015-09-07", + def test_memorial_day(self): + name = "Memorial Day" + self.assertNoHolidayName(name) + nl_holidays = self.prov_hols["NL"] + self.assertHolidayName(name, nl_holidays, (f"{year}-07-01" for year in range(1917, 2050))) + self.assertNoHolidayName(name, nl_holidays, range(1900, 1917)) + + def test_st_patricks_day(self): + name = "St. Patrick's Day" + self.assertNoHolidayName(name, self.prov_hols["NL"]) + nl_opt_holidays = CA(subdiv="NL", categories=(OPTIONAL,)) + dts = ( + "1900-03-19", + "1999-03-15", + "2000-03-20", + "2012-03-19", + "2013-03-18", + "2014-03-17", + "2015-03-16", + "2016-03-14", + "2020-03-16", ) + self.assertNoHoliday(dts) + self.assertNoHolidayName(name) + self.assertHolidayName(name, nl_opt_holidays, dts) + self.assertNoHoliday(nl_opt_holidays, "1899-03-20") - def test_national_day_for_truth_and_reconciliation(self): - bc_holidays = self.prov_hols["BC"] - mb_holidays = self.prov_hols["MB"] - ns_holidays = self.prov_hols["NS"] - - dt = ("1991-09-30", "2020-09-30") - self.assertNoHoliday(dt) - self.assertNoHoliday(mb_holidays, dt) - self.assertNoHoliday(ns_holidays, dt) - - dt = ("2021-09-30", "2022-09-30") - self.assertHoliday(mb_holidays, dt) - self.assertHoliday(ns_holidays, dt) - self.assertNoHoliday(dt) - - dt = ("2023-09-30", "2024-09-30", "2030-09-30") - self.assertHoliday(mb_holidays, dt) - self.assertHoliday(ns_holidays, dt) - self.assertHoliday(bc_holidays, dt) - self.assertNoHoliday(dt) - - def test_thanksgiving(self): - nb_holidays = self.prov_hols["NB"] - nl_holidays = self.prov_hols["NL"] - ns_holidays = self.prov_hols["NS"] - pe_holidays = self.prov_hols["PE"] + def test_st_georges_day(self): + name = "St. George's Day" + self.assertNoHolidayName(name, self.prov_hols["NL"]) + nl_opt_holidays = CA(subdiv="NL", categories=(OPTIONAL,)) + dts = ( + "1990-04-23", + "1999-04-26", + "2010-04-19", + "2016-04-25", + "2020-04-20", + ) + self.assertNoHoliday(dts) + self.assertNoHolidayName(name) + self.assertHolidayName(name, nl_opt_holidays, dts) + self.assertNoHoliday(nl_opt_holidays, "1989-04-24") + + def test_discovery_day_nl(self): + name = "Discovery Day" + self.assertNoHolidayName(name, self.prov_hols["NL"]) + nl_opt_holidays = CA(subdiv="NL", categories=(OPTIONAL,)) + dts = ( + "1997-06-23", + "1999-06-21", + "2000-06-26", + "2010-06-21", + "2016-06-27", + "2020-06-22", + ) + self.assertNoHoliday(dts) + self.assertNoHolidayName(name) + self.assertHoliday(nl_opt_holidays, dts) + self.assertNoHoliday(nl_opt_holidays, "1996-06-24") + + def test_orangemans_day(self): + name = "Orangemen's Day" + self.assertNoHolidayName(name, self.prov_hols["NL"]) + nl_opt_holidays = CA(subdiv="NL", categories=(OPTIONAL,)) + dts = ( + "1900-07-09", + "1999-07-12", + "2000-07-10", + "2010-07-12", + "2016-07-11", + "2020-07-13", + ) + self.assertNoHoliday(dts) + self.assertNoHolidayName(name) + self.assertHoliday(nl_opt_holidays, dts) + self.assertNoHoliday(nl_opt_holidays, "1899-07-10") - dt = ( - "1931-10-12", - "1935-10-25", - "1990-10-08", - "1999-10-11", - "2000-10-09", - "2013-10-14", - "2020-10-12", + def test_discovery_day_yt(self): + name = "Discovery Day" + yt_holidays = self.prov_hols["YT"] + dts = ( + "1912-08-19", + "1999-08-16", + "2000-08-21", + "2006-08-21", + "2016-08-15", + "2020-08-17", ) - self.assertHoliday(dt) - self.assertNoHoliday(nb_holidays, dt) - self.assertNoHoliday(nl_holidays, dt) - self.assertNoHoliday(ns_holidays, dt) - self.assertNoHoliday(pe_holidays, dt) + self.assertNoHoliday(dts) + self.assertNoHolidayName(name) + self.assertHoliday(yt_holidays, dts) + self.assertNoHoliday(yt_holidays, "1911-08-21") - def test_remembrance_day(self): - ab_holidays = self.prov_hols["AB"] - nl_holidays = self.prov_hols["NL"] - self.assertNoHoliday(nl_holidays, "1930-11-11") - self.assertNoHoliday(ab_holidays, "1930-11-11") + def test_national_aboriginal_day(self): + name = "National Aboriginal Day" + nt_holidays = self.prov_hols["NT"] + yt_holidays = self.prov_hols["YT"] + self.assertHolidayName(name, nt_holidays, (f"{year}-06-21" for year in range(1996, 2050))) + self.assertNoHolidayName(nt_holidays, range(1867, 1996)) + self.assertHolidayName(name, yt_holidays, (f"{year}-06-21" for year in range(2017, 2050))) + self.assertNoHolidayName(yt_holidays, range(1867, 2017)) + self.assertNoHoliday(f"{year}-06-21" for year in range(1996, 2050)) + self.assertNoHolidayName(name) - self.assertNoHoliday(f"{year}-11-11" for year in range(1931, 2050)) - self.assertHoliday(ab_holidays, (f"{year}-11-11" for year in range(1931, 2050))) - self.assertHoliday(nl_holidays, (f"{year}-11-11" for year in range(1931, 2050))) + def test_nunavut_day(self): + name = "Nunavut Day" + self.assertNoHolidayName(name) + self.assertNoHoliday(f"{year}-07-09" for year in range(2001, 2050)) + self.assertNoHolidayName(name, self.prov_hols["NU"]) + nu_opt_holidays = CA(subdiv="NU", categories=(OPTIONAL,)) + self.assertNoHoliday(nu_opt_holidays, "1999-07-09", "2000-07-09") + self.assertHoliday(nu_opt_holidays, "2000-04-01") + self.assertHoliday(nu_opt_holidays, (f"{year}-07-09" for year in range(2001, 2050))) - self.assertNoHoliday(ab_holidays, "2007-11-12") - self.assertHoliday(nl_holidays, "2007-11-12") - self.assertNoNonObservedHoliday(Canada(subdiv="AB", observed=False), "2007-11-12") - self.assertNoNonObservedHoliday(Canada(subdiv="NL", observed=False), "2007-11-12") + def test_national_patriots_day(self): + name = "National Patriots' Day" + self.assertNoHolidayName(name) + qc_holidays = self.prov_hols["QC"] + self.assertHolidayName( + name, + qc_holidays, + "2010-05-24", + "2015-05-18", + "2020-05-18", + "2021-05-24", + "2022-05-23", + ) + self.assertNoHolidayName(name, qc_holidays, range(1867, 2003)) - def test_christmas_day(self): - self.assertHoliday(f"{year}-12-25" for year in range(1900, 2050)) - self.assertHoliday("2010-12-27", "2011-12-27") - self.assertNoNonObservedHoliday("2010-12-27", "2011-12-27") - self.assertNotIn("Christmas Day (Observed)", self.holidays["2011-12-26"]) - self.assertHolidayName("Christmas Day (Observed)", "2011-12-27") + def test_st_jean_baptiste_day(self): + name = "St. Jean Baptiste Day" + self.assertNoHolidayName(name) + qc_holidays = self.prov_hols["QC"] + self.assertHoliday(qc_holidays, (f"{year}-06-24" for year in range(1925, 2050))) + self.assertNoHoliday(qc_holidays, (f"{year}-06-24" for year in range(1867, 1925))) + self.assertNoHoliday(f"{year}-06-24" for year in range(1925, 2050)) + self.assertHoliday(qc_holidays, "2001-06-25") + self.assertNoNonObservedHoliday(Canada(subdiv="QC", observed=False), "2001-06-25") - def test_boxing_day(self): - self.assertHoliday(f"{year}-12-26" for year in range(1900, 2050)) - self.assertHoliday("2009-12-28", "2010-12-27") - self.assertNoNonObservedHoliday("2009-12-28", "2010-12-27") + def test_yukon_heritage_day(self): + name = "Heritage Day" + self.assertNoHolidayName(name) + self.assertNoHolidayName(name, self.prov_hols["YT"]) + yt_opt_holidays = CA(subdiv="YT", categories=(OPTIONAL,)) + dts = ( + "2017-02-24", + "2018-02-23", + "2019-02-22", + "2020-02-21", + "2021-02-26", + "2022-02-25", + ) + self.assertHolidayName(name, yt_opt_holidays, dts) def test_queens_funeral(self): for prov, holidays in self.prov_hols.items(): @@ -384,20 +756,94 @@ def test_queens_funeral(self): else: self.assertNoHoliday(holidays, "2022-09-19") + def test_public_2022(self): + self.assertHolidays( + Canada(years=2022), + ("2022-01-01", "New Year's Day"), + ("2022-01-03", "New Year's Day (Observed)"), + ("2022-04-15", "Good Friday"), + ("2022-07-01", "Canada Day"), + ("2022-09-05", "Labour Day"), + ("2022-12-25", "Christmas Day"), + ("2022-12-26", "Christmas Day (Observed)"), + ) + + def test_government_2022(self): + self.assertHolidays( + Canada(years=2022, categories=(GOVERNMENT,)), + ("2022-01-01", "New Year's Day"), + ("2022-01-03", "New Year's Day (Observed)"), + ("2022-04-15", "Good Friday"), + ("2022-05-23", "Victoria Day"), + ("2022-07-01", "Canada Day"), + ("2022-09-05", "Labour Day"), + ("2022-09-30", "National Day for Truth and Reconciliation"), + ("2022-10-10", "Thanksgiving Day"), + ("2022-11-11", "Remembrance Day"), + ("2022-12-25", "Christmas Day"), + ("2022-12-26", "Boxing Day"), + ("2022-12-27", "Christmas Day (Observed)"), + ) + + def test_optional_2022(self): + self.assertHolidays( + Canada(years=2022, categories=(OPTIONAL,)), + ("2022-12-25", "Christmas Day"), + ("2022-12-26", "Boxing Day"), + ("2022-12-27", "Christmas Day (Observed)"), + ) + + def test_all_holidays_present(self): + y_2022 = set() + for prov in Canada.subdivisions: + y_2022.update(Canada(years=2022, subdiv=prov, observed=False).values()) + all_h = { # Holidays names in their chronological order. + "New Year's Day", + "Family Day", + "Heritage Day", + "Islander Day", + "Louis Riel Day", + "Good Friday", + "National Patriots' Day", + "Victoria Day", + "National Aboriginal Day", + "St. Jean Baptiste Day", + "Canada Day", + "Canada Day; Memorial Day", + "British Columbia Day", + "Civic Holiday", + "New Brunswick Day", + "Saskatchewan Day", + "Discovery Day", + "Labour Day", + "Funeral of Her Majesty the Queen Elizabeth II", + "National Day for Truth and Reconciliation", + "Thanksgiving Day", + "Remembrance Day", + "Christmas Day", + "Boxing Day", + } + + self.assertEqual( + all_h, + y_2022, + f"missing: {all_h - y_2022 if len(all_h - y_2022) > 0 else 'no'}," + f" extra: {y_2022 - all_h if len(y_2022 - all_h) > 0 else 'no'}", + ) + def test_l10n_default(self): self.assertLocalizedHolidays( ("2022-01-01", "New Year's Day"), ("2022-01-03", "New Year's Day (Observed)"), - ("2022-02-21", "Family Day"), ("2022-04-15", "Good Friday"), - ("2022-04-18", "Easter Monday"), ("2022-05-23", "Victoria Day"), ("2022-07-01", "Canada Day"), - ("2022-08-01", "Civic Holiday"), ("2022-09-05", "Labour Day"), - ("2022-10-10", "Thanksgiving"), + ("2022-09-30", "National Day for Truth and Reconciliation"), + ("2022-10-10", "Thanksgiving Day"), + ("2022-11-11", "Remembrance Day"), ("2022-12-25", "Christmas Day"), - ("2022-12-26", "Boxing Day"), + ("2022-12-26", "Boxing Day; Christmas Day (Observed)"), ("2022-12-27", "Christmas Day (Observed)"), ) @@ -406,16 +852,15 @@ def test_l10n_ar(self): "ar", ("2022-01-01", "يوم السنة الجديدة"), ("2022-01-03", "(تمت ملاحظته) يوم السنة الجديدة"), - ("2022-02-21", "يوم العائلة"), ("2022-04-15", "جمعة جيدة"), - ("2022-04-18", "عيد الفصح الاثنين"), ("2022-05-23", "يوم فيكتوريا"), ("2022-07-01", "يوم كندا"), - ("2022-08-01", "عطلة المدنية"), ("2022-09-05", "عيد العمال"), + ("2022-09-30", "اليوم الوطني للحقيقة والمصالحة"), ("2022-10-10", "عيد الشكر"), + ("2022-11-11", "يوم الذكرى"), ("2022-12-25", "عيد الميلاد"), - ("2022-12-26", "يوم الملاكمة"), + ("2022-12-26", "(تمت ملاحظته) عيد الميلاد; يوم الملاكمة"), ("2022-12-27", "(تمت ملاحظته) عيد الميلاد"), ) @@ -424,16 +869,15 @@ def test_l10n_fr(self): "fr", ("2022-01-01", "Jour de l'an"), ("2022-01-03", "Jour de l'an (Observé)"), - ("2022-02-21", "Fête de la famille"), ("2022-04-15", "Vendredi saint"), - ("2022-04-18", "Lundi de Pâques"), ("2022-05-23", "Fête de la Reine"), ("2022-07-01", "Fête du Canada"), - ("2022-08-01", "Premier lundi d'août"), ("2022-09-05", "Fête du Travail"), + ("2022-09-30", "Journée nationale de la vérité et de la réconciliation"), ("2022-10-10", "Action de grâce"), + ("2022-11-11", "Jour du Souvenir"), ("2022-12-25", "Jour de Noël"), - ("2022-12-26", "Boxing Day"), + ("2022-12-26", "Boxing Day; Jour de Noël (Observé)"), ("2022-12-27", "Jour de Noël (Observé)"), ) @@ -442,15 +886,14 @@ def test_l10n_th(self): "th", ("2022-01-01", "วันขึ้นปีใหม่"), ("2022-01-03", "ชดเชยวันขึ้นปีใหม่"), - ("2022-02-21", "วันครอบครัว"), ("2022-04-15", "วันศุกร์ประเสริฐ"), - ("2022-04-18", "วันจันทร์อีสเตอร์"), ("2022-05-23", "วันวิคตอเรีย"), ("2022-07-01", "วันชาติแคนาดา"), - ("2022-08-01", "วันหยุดราชการ"), ("2022-09-05", "วันแรงงาน"), + ("2022-09-30", "วันชาติแห่งความจริงและการปรองดอง"), ("2022-10-10", "วันขอบคุณพระเจ้า"), + ("2022-11-11", "วันรำลึก"), ("2022-12-25", "วันคริสต์มาส"), - ("2022-12-26", "วันเปิดกล่องของขวัญ"), + ("2022-12-26", "ชดเชยวันคริสต์มาส; วันเปิดกล่องของขวัญ"), ("2022-12-27", "ชดเชยวันคริสต์มาส"), ) diff --git a/tests/countries/test_liechtenstein.py b/tests/countries/test_liechtenstein.py index 750b7c078..da925dd0c 100644 --- a/tests/countries/test_liechtenstein.py +++ b/tests/countries/test_liechtenstein.py @@ -10,14 +10,17 @@ # License: MIT (see LICENSE file) # Copyright: Kateryna Golovanova , 2022 +from holidays.constants import BANK from holidays.countries.liechtenstein import Liechtenstein, LI, LIE from tests.common import TestCase -class TestLI(TestCase): +class TestLiechtenstein(TestCase): @classmethod def setUpClass(cls): - super().setUpClass(Liechtenstein, years=range(1900, 2050)) + years = range(1900, 2050) + super().setUpClass(Liechtenstein, years=years) + cls.bank_holidays = Liechtenstein(categories=(BANK,), years=years) def test_country_aliases(self): self.assertCountryAliases(Liechtenstein, LI, LIE) @@ -26,7 +29,12 @@ def test_new_years(self): self.assertHolidayName("Neujahr", (f"{year}-01-01" for year in range(1900, 2050))) def test_saint_berchtolds_day(self): - self.assertHolidayName("Berchtoldstag", (f"{year}-01-02" for year in range(1900, 2050))) + name = "Berchtoldstag" + self.assertHolidayName( + name, self.bank_holidays, (f"{year}-01-02" for year in range(1900, 2050)) + ) + self.assertNoHoliday(f"{year}-01-02" for year in range(1900, 2050)) + self.assertNoHolidayName(name) def test_epiphany(self): self.assertHolidayName( @@ -37,8 +45,8 @@ def test_candlemas(self): self.assertHolidayName("Mariä Lichtmess", (f"{year}-02-02" for year in range(1900, 2050))) def test_shrove_tuesday(self): - self.assertHolidayName( - "Fasnachtsdienstag", + name = "Fasnachtsdienstag" + dt = ( "1900-02-27", "1901-02-19", "1902-02-11", @@ -50,13 +58,16 @@ def test_shrove_tuesday(self): "2021-02-16", "2022-03-01", ) + self.assertHolidayName(name, self.bank_holidays, dt) + self.assertNoHoliday(dt) + self.assertNoHolidayName(name) def test_saint_josephs_day(self): self.assertHolidayName("Josefstag", (f"{year}-03-19" for year in range(1900, 2050))) def test_good_friday(self): - self.assertHolidayName( - "Karfreitag", + name = "Karfreitag" + dt = ( "1900-04-13", "1901-04-05", "1902-03-28", @@ -68,6 +79,9 @@ def test_good_friday(self): "2021-04-02", "2022-04-15", ) + self.assertHolidayName(name, self.bank_holidays, dt) + self.assertNoHoliday(dt) + self.assertNoHolidayName(name) def test_easter(self): self.assertHolidayName( @@ -175,7 +189,12 @@ def test_immaculate_conception(self): self.assertHolidayName("Mariä Empfängnis", (f"{year}-12-08" for year in range(1900, 2050))) def test_christmas_eve(self): - self.assertHolidayName("Heiligabend", (f"{year}-12-24" for year in range(1900, 2050))) + name = "Heiligabend" + self.assertHolidayName( + name, self.bank_holidays, (f"{year}-12-24" for year in range(1900, 2050)) + ) + self.assertNoHoliday(f"{year}-12-24" for year in range(1900, 2050)) + self.assertNoHolidayName(name) def test_christmas_day(self): self.assertHolidayName("Weihnachten", (f"{year}-12-25" for year in range(1900, 2050))) @@ -184,18 +203,20 @@ def test_st_stephens_day(self): self.assertHolidayName("Stefanstag", (f"{year}-12-26" for year in range(1900, 2050))) def test_new_years_eve(self): - self.assertHolidayName("Silvester", (f"{year}-12-31" for year in range(1900, 2050))) + name = "Silvester" + self.assertHolidayName( + name, self.bank_holidays, (f"{year}-12-31" for year in range(1900, 2050)) + ) + self.assertNoHoliday(f"{year}-12-31" for year in range(1900, 2050)) + self.assertNoHolidayName(name) def test_2022(self): self.assertHolidays( Liechtenstein(years=2022), ("2022-01-01", "Neujahr"), - ("2022-01-02", "Berchtoldstag"), ("2022-01-06", "Heilige Drei Könige"), ("2022-02-02", "Mariä Lichtmess"), - ("2022-03-01", "Fasnachtsdienstag"), ("2022-03-19", "Josefstag"), - ("2022-04-15", "Karfreitag"), ("2022-04-17", "Ostersonntag"), ("2022-04-18", "Ostermontag"), ("2022-05-01", "Tag der Arbeit"), @@ -207,9 +228,17 @@ def test_2022(self): ("2022-09-08", "Mariä Geburt"), ("2022-11-01", "Allerheiligen"), ("2022-12-08", "Mariä Empfängnis"), - ("2022-12-24", "Heiligabend"), ("2022-12-25", "Weihnachten"), ("2022-12-26", "Stefanstag"), + ) + + def test_2022_bank(self): + self.assertHolidays( + Liechtenstein(categories=(BANK,), years=2022), + ("2022-01-02", "Berchtoldstag"), + ("2022-03-01", "Fasnachtsdienstag"), + ("2022-04-15", "Karfreitag"), + ("2022-12-24", "Heiligabend"), ("2022-12-31", "Silvester"), ) diff --git a/tests/countries/test_saudi_arabia.py b/tests/countries/test_saudi_arabia.py index 361ebdbc3..6d98f965d 100644 --- a/tests/countries/test_saudi_arabia.py +++ b/tests/countries/test_saudi_arabia.py @@ -80,7 +80,6 @@ def test_national_day_overlaps_hijri_holiday(self): "2009-09-23", "2015-09-23", "2048-09-23", - "2074-09-23", ) def test_founding_day(self): diff --git a/tests/countries/test_thailand.py b/tests/countries/test_thailand.py index 3921554a2..ebe28e5bd 100644 --- a/tests/countries/test_thailand.py +++ b/tests/countries/test_thailand.py @@ -9,6 +9,7 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) +from holidays.constants import ARMED_FORCES, BANK, GOVERNMENT, PUBLIC, SCHOOL, WORKDAY from holidays.countries.thailand import Thailand, TH, THA from tests.common import TestCase @@ -100,12 +101,21 @@ def test_special_holidays(self): "2023-07-31", ) - def test_2022(self): + def test_2022_all(self): self.assertHolidays( - Thailand(years=2022), + Thailand(categories=(ARMED_FORCES, GOVERNMENT, PUBLIC, SCHOOL, WORKDAY), years=2022), ("2022-01-01", "วันขึ้นปีใหม่"), ("2022-01-03", "ชดเชยวันขึ้นปีใหม่"), + ("2022-01-08", "วันเด็กแห่งชาติ"), + ("2022-01-13", "วันการบินแห่งชาติ"), + ("2022-01-14", "วันอนุรักษ์ทรัพยากรป่าไม้ของชาติ"), + ("2022-01-16", "วันครู"), + ("2022-01-17", "วันพ่อขุนรามคำแหงมหาราช"), + ("2022-01-18", "วันกองทัพไทย"), + ("2022-02-03", "วันทหารผ่านศึก"), ("2022-02-16", "วันมาฆบูชา"), + ("2022-02-26", "วันศิลปินแห่งชาติ"), + ("2022-03-08", "วันสตรีสากล"), ("2022-04-06", "วันจักรี"), ("2022-04-13", "วันสงกรานต์"), ("2022-04-14", "วันสงกรานต์"), @@ -132,6 +142,8 @@ def test_2022(self): ), ("2022-07-29", "วันหยุดพิเศษ (เพิ่มเติม)"), ("2022-08-12", "วันเฉลิมพระชนมพรรษาสมเด็จพระบรมราชชนนีพันปีหลวง; วันแม่แห่งชาติ"), + ("2022-08-18", "วันวิทยาศาสตร์แห่งชาติ"), + ("2022-09-28", "วันพระราชทานธงชาติไทย"), ( "2022-10-13", ( @@ -142,6 +154,7 @@ def test_2022(self): ("2022-10-14", "วันหยุดพิเศษ (เพิ่มเติม)"), ("2022-10-23", "วันปิยมหาราช"), ("2022-10-24", "ชดเชยวันปิยมหาราช"), + ("2022-11-08", "วันลอยกระทง"), ( "2022-12-05", ( @@ -167,6 +180,33 @@ def test_new_years_day(self): "2028-01-03", ) + def test_national_childrens_day(self): + name = "วันเด็กแห่งชาติ" + + dt = ( + # First Iteration + "1955-10-03", + # Second and Current Iteration + "2010-01-09", + "2011-01-08", + "2012-01-14", + "2013-01-12", + "2014-01-11", + "2015-01-10", + "2016-01-09", + "2017-01-14", + "2018-01-13", + "2019-01-12", + "2020-01-11", + "2021-01-09", + "2022-01-08", + "2023-01-14", + "2024-01-13", + "2025-01-11", + ) + self.assertHolidayName(name, dt) + self.assertNoHolidayName(name, 1954, 1964) + def test_chakri_memorial_day(self): self.assertHoliday(f"{year}-04-06" for year in range(1941, 2058)) @@ -561,33 +601,173 @@ def test_khao_phansa(self): def test_raeknakhwan(self): name = "วันพืชมงคล" - dt = ( - "2011-05-13", - "2012-05-09", - "2013-05-13", - "2014-05-09", - "2015-05-13", - "2016-05-09", - "2017-05-12", - "2018-05-14", - "2019-05-09", - "2020-05-11", - "2021-05-13", - "2022-05-17", - "2023-05-11", + self.assertHolidays( + Thailand(categories=(GOVERNMENT,), years=range(1997, 2024)), + ("1997-05-13", name), + ("1998-05-13", name), + ("2000-05-15", name), + ("2001-05-16", name), + ("2002-05-09", name), + ("2003-05-08", name), + ("2004-05-07", name), + ("2005-05-11", name), + ("2006-05-11", name), + ("2007-05-10", name), + ("2008-05-09", name), + ("2009-05-11", name), + ("2010-05-10", name), + ("2011-05-13", name), + ("2012-05-09", name), + ("2013-05-13", name), + ("2014-05-09", name), + ("2015-05-13", name), + ("2016-05-09", name), + ("2017-05-12", name), + ("2018-05-14", name), + ("2019-05-09", name), + ("2020-05-11", name), + ("2021-05-13", name), + ("2022-05-17", name), + ("2023-05-11", name), + ) + + def test_armed_forces_holiday(self): + name = "วันกองทัพไทย" + self.assertHolidays( + Thailand(categories=(ARMED_FORCES,), years=range(1958, 1960)), ("1959-04-08", name) + ) + self.assertHolidays( + Thailand(categories=(ARMED_FORCES,), years=range(1979, 1981)), + ("1979-04-08", name), + ("1980-01-25", name), + ) + self.assertHolidays( + Thailand(categories=(ARMED_FORCES,), years=range(2006, 2008)), + ("2006-01-25", name), + ("2007-01-18", name), + ) + + def test_bank_holiday(self): + a_name = "วันหยุดเพิ่มเติมสำหรับการปิดบัญชีประจำปีของธนาคารเพื่อการเกษตรและสหกรณ์การเกษตร" + m_name = "วันหยุดภาคครึ่งปีของสถาบันการเงินและสถาบันการเงินเฉพาะกิจ" + + # Start + self.assertHolidays( + Thailand(categories=(BANK,), years=range(1942, 1944)), + ("1943-04-01", a_name), + ("1943-07-01", m_name), + ) + # End + self.assertHolidays( + Thailand(categories=(BANK,), years=range(2017, 2023)), + ("2017-04-01", a_name), + ("2017-07-01", m_name), + ("2018-04-01", a_name), + ("2018-07-01", m_name), + ("2019-04-01", a_name), + ("2020-04-01", a_name), + ("2021-04-01", a_name), + ) + + def test_school_holiday(self): + self.assertHolidays( + Thailand(categories=(SCHOOL,), years=range(1956, 1958)), + ("1957-01-16", "วันครู"), + ) + + def test_workday_1947(self): + self.assertHolidays( + Thailand(categories=(WORKDAY,), years=1947), + ("1947-11-27", "วันลอยกระทง"), + ) + + def test_workday_1948(self): + self.assertHolidays( + Thailand(categories=(WORKDAY,), years=1948), + ("1948-02-03", "วันทหารผ่านศึก"), + ("1948-11-15", "วันลอยกระทง"), + ) + + def test_workday_1982(self): + self.assertHolidays( + Thailand(categories=(WORKDAY,), years=1982), + ("1982-02-03", "วันทหารผ่านศึก"), + ("1982-08-18", "วันวิทยาศาสตร์แห่งชาติ"), + ("1982-10-31", "วันลอยกระทง"), ) - self.assertHolidayName(name, dt) - self.assertNoHolidayName(name, 1956, 1999) - self.assertHolidayName(name, (f"{year}-05-13" for year in range(1957, 1997))) + def test_workday_1985(self): + self.assertHolidays( + Thailand(categories=(WORKDAY,), years=1985), + ("1985-02-03", "วันทหารผ่านศึก"), + ("1985-02-26", "วันศิลปินแห่งชาติ"), + ("1985-08-18", "วันวิทยาศาสตร์แห่งชาติ"), + ("1985-11-26", "วันลอยกระทง"), + ) - # No Royal Ploughing Ceremony on weekend for 1997-2023 + def test_workday_1989(self): + self.assertHolidays( + Thailand(categories=(WORKDAY,), years=1989), + ("1989-02-03", "วันทหารผ่านศึก"), + ("1989-02-26", "วันศิลปินแห่งชาติ"), + ("1989-03-08", "วันสตรีสากล"), + ("1989-08-18", "วันวิทยาศาสตร์แห่งชาติ"), + ("1989-11-12", "วันลอยกระทง"), + ) + + def test_workday_1990(self): + self.assertHolidays( + Thailand(categories=(WORKDAY,), years=1990), + ("1990-01-14", "วันอนุรักษ์ทรัพยากรป่าไม้ของชาติ"), + ("1990-01-17", "วันพ่อขุนรามคำแหงมหาราช"), + ("1990-02-03", "วันทหารผ่านศึก"), + ("1990-02-26", "วันศิลปินแห่งชาติ"), + ("1990-03-08", "วันสตรีสากล"), + ("1990-08-18", "วันวิทยาศาสตร์แห่งชาติ"), + ("1990-11-02", "วันลอยกระทง"), + ) + + def test_workday_1995(self): + self.assertHolidays( + Thailand(categories=(WORKDAY,), years=1995), + ("1995-01-13", "วันการบินแห่งชาติ"), + ("1995-01-14", "วันอนุรักษ์ทรัพยากรป่าไม้ของชาติ"), + ("1995-01-17", "วันพ่อขุนรามคำแหงมหาราช"), + ("1995-02-03", "วันทหารผ่านศึก"), + ("1995-02-26", "วันศิลปินแห่งชาติ"), + ("1995-03-08", "วันสตรีสากล"), + ("1995-08-18", "วันวิทยาศาสตร์แห่งชาติ"), + ("1995-11-06", "วันลอยกระทง"), + ) + + def test_workday_2017(self): + self.assertHolidays( + Thailand(categories=(WORKDAY,), years=2017), + ("2017-01-13", "วันการบินแห่งชาติ"), + ("2017-01-14", "วันอนุรักษ์ทรัพยากรป่าไม้ของชาติ"), + ("2017-01-17", "วันพ่อขุนรามคำแหงมหาราช"), + ("2017-02-03", "วันทหารผ่านศึก"), + ("2017-02-26", "วันศิลปินแห่งชาติ"), + ("2017-03-08", "วันสตรีสากล"), + ("2017-08-18", "วันวิทยาศาสตร์แห่งชาติ"), + ("2017-09-28", "วันพระราชทานธงชาติไทย"), + ("2017-11-03", "วันลอยกระทง"), + ) def test_l10n_default(self): self.assertLocalizedHolidays( ("2022-01-01", "วันขึ้นปีใหม่"), ("2022-01-03", "ชดเชยวันขึ้นปีใหม่"), + ("2022-01-08", "วันเด็กแห่งชาติ"), + ("2022-01-13", "วันการบินแห่งชาติ"), + ("2022-01-14", "วันอนุรักษ์ทรัพยากรป่าไม้ของชาติ"), + ("2022-01-16", "วันครู"), + ("2022-01-17", "วันพ่อขุนรามคำแหงมหาราช"), + ("2022-01-18", "วันกองทัพไทย"), + ("2022-02-03", "วันทหารผ่านศึก"), ("2022-02-16", "วันมาฆบูชา"), + ("2022-02-26", "วันศิลปินแห่งชาติ"), + ("2022-03-08", "วันสตรีสากล"), ("2022-04-06", "วันจักรี"), ("2022-04-13", "วันสงกรานต์"), ("2022-04-14", "วันสงกรานต์"), @@ -614,6 +794,8 @@ def test_l10n_default(self): ), ("2022-07-29", "วันหยุดพิเศษ (เพิ่มเติม)"), ("2022-08-12", "วันเฉลิมพระชนมพรรษาสมเด็จพระบรมราชชนนีพันปีหลวง; วันแม่แห่งชาติ"), + ("2022-08-18", "วันวิทยาศาสตร์แห่งชาติ"), + ("2022-09-28", "วันพระราชทานธงชาติไทย"), ( "2022-10-13", ( @@ -624,6 +806,7 @@ def test_l10n_default(self): ("2022-10-14", "วันหยุดพิเศษ (เพิ่มเติม)"), ("2022-10-23", "วันปิยมหาราช"), ("2022-10-24", "ชดเชยวันปิยมหาราช"), + ("2022-11-08", "วันลอยกระทง"), ( "2022-12-05", ( @@ -642,7 +825,16 @@ def test_l10n_en_US(self): "en_US", ("2022-01-01", "New Year's Day"), ("2022-01-03", "New Year's Day (in lieu)"), + ("2022-01-08", "National Children's Day"), + ("2022-01-13", "National Aviation Day"), + ("2022-01-14", "National Forest Conservation Day"), + ("2022-01-16", "Teacher's Day"), + ("2022-01-17", "HM King Ramkamhaeng Memorial Day"), + ("2022-01-18", "Royal Thai Armed Forces Day"), + ("2022-02-03", "Thai Veterans Day"), ("2022-02-16", "Makha Bucha"), + ("2022-02-26", "National Artist Day"), + ("2022-03-08", "International Women's Day"), ("2022-04-06", "Chakri Memorial Day"), ("2022-04-13", "Songkran Festival"), ("2022-04-14", "Songkran Festival"), @@ -663,10 +855,13 @@ def test_l10n_en_US(self): "2022-08-12", "HM Queen Sirikit The Queen Mother's Birthday; National Mother's Day", ), + ("2022-08-18", "National Science Day"), + ("2022-09-28", "Thai National Flag Day"), ("2022-10-13", "HM King Bhumibol Adulyadej the Great Memorial Day"), ("2022-10-14", "Bridge Public Holiday"), ("2022-10-23", "HM King Chulalongkorn Memorial Day"), ("2022-10-24", "HM King Chulalongkorn Memorial Day (in lieu)"), + ("2022-11-08", "Loy Krathong"), ( "2022-12-05", ( diff --git a/tests/countries/test_united_kingdom.py b/tests/countries/test_united_kingdom.py index 285b4c09d..e08a5709b 100644 --- a/tests/countries/test_united_kingdom.py +++ b/tests/countries/test_united_kingdom.py @@ -72,25 +72,27 @@ def test_new_year_scotland(self): name_new_year = "New Year's Day" name_new_year_holiday = "New Year Holiday" ny_obs_dt = ( - "2000-01-04", - "2005-01-04", + "2000-01-03", + "2005-01-03", "2006-01-02", - "2011-01-04", + "2011-01-03", "2012-01-02", "2017-01-02", - "2022-01-04", + "2022-01-03", + "2023-01-02", ) nyh_obs_dt = ( - "2000-01-03", - "2005-01-03", + "2000-01-04", + "2005-01-04", "2006-01-03", "2010-01-04", - "2011-01-03", + "2011-01-04", "2012-01-03", "2016-01-04", "2017-01-03", "2021-01-04", - "2022-01-03", + "2022-01-04", + "2023-01-03", ) for subdiv in ("SCT", "Scotland"): @@ -221,10 +223,20 @@ def test_spring_bank_holiday(self): def test_battle_of_the_boyne_day(self): name = "Battle of the Boyne" + obs_dt = ( + "2003-07-14", + "2008-07-14", + "2009-07-13", + "2014-07-14", + "2015-07-13", + "2020-07-13", + ) for subdiv in ("NIR", "Northern Ireland"): self.assertHolidayName( name, self.subdiv_holidays[subdiv], (f"{year}-07-12" for year in range(1950, 2050)) ) + self.assertHolidayName(f"{name} (Observed)", self.subdiv_holidays[subdiv], obs_dt) + self.assertNoNonObservedHoliday(UnitedKingdom(subdiv=subdiv, observed=False), obs_dt) for subdiv in ("ENG", "SCT", "WLS", "England", "Scotland", "Wales"): self.assertNoHoliday( @@ -305,6 +317,12 @@ def test_late_summer_bank_holiday(self): def test_st_andrews_day(self): name = "St. Andrew's Day" + obs_dt = ( + "2008-12-01", + "2013-12-02", + "2014-12-01", + "2019-12-02", + ) for subdiv in ("SCT", "Scotland"): self.assertHolidayName( name, self.subdiv_holidays[subdiv], (f"{year}-11-30" for year in range(2006, 2050)) @@ -313,6 +331,9 @@ def test_st_andrews_day(self): self.subdiv_holidays[subdiv], (f"{year}-11-30" for year in range(1950, 2006)) ) self.assertNoHolidayName(name, self.subdiv_holidays[subdiv], range(1950, 2006)) + self.assertHolidayName(f"{name} (Observed)", self.subdiv_holidays[subdiv], obs_dt) + self.assertNoNonObservedHoliday(UnitedKingdom(subdiv=subdiv, observed=False), obs_dt) + for subdiv in ( "ENG", "NIR", diff --git a/tests/countries/test_vanuatu.py b/tests/countries/test_vanuatu.py index 52395b97c..b13377e91 100644 --- a/tests/countries/test_vanuatu.py +++ b/tests/countries/test_vanuatu.py @@ -186,9 +186,12 @@ def test_family_day(self): name = "Family Day" self.assertHolidayName(name, (f"{year}-12-26" for year in range(1981, 2050))) dt = ( + "2004-12-27", "2005-12-27", + "2010-12-27", "2011-12-27", "2016-12-27", + "2021-12-27", "2022-12-27", ) self.assertHolidayName(f"{name} (Observed)", dt) diff --git a/tests/test_registry.py b/tests/test_registry.py index 8f0b5d8f5..13f735ca7 100644 --- a/tests/test_registry.py +++ b/tests/test_registry.py @@ -11,7 +11,6 @@ import importlib import inspect -import sys import warnings from unittest import TestCase @@ -19,12 +18,12 @@ import holidays from holidays import countries, financial, registry -from tests.common import PYTHON_VERSION +from tests.common import PYTHON_LATEST_SUPPORTED_VERSION, PYTHON_VERSION class TestEntityLoader(TestCase): @pytest.mark.skipif( - sys.version_info < PYTHON_VERSION, + PYTHON_VERSION != PYTHON_LATEST_SUPPORTED_VERSION, reason="Run once on the latest Python version only", ) def test_countries_imports(self): @@ -67,7 +66,7 @@ def test_country_str(self): ) @pytest.mark.skipif( - sys.version_info < PYTHON_VERSION, + PYTHON_VERSION != PYTHON_LATEST_SUPPORTED_VERSION, reason="Run once on the latest Python version only", ) def test_financial_imports(self): diff --git a/tests/test_utils.py b/tests/test_utils.py index d8e2c655d..3d7ba7a15 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -9,7 +9,6 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -import sys import unittest import warnings from datetime import date @@ -28,7 +27,7 @@ list_supported_countries, list_supported_financial, ) -from tests.common import PYTHON_VERSION +from tests.common import PYTHON_LATEST_SUPPORTED_VERSION, PYTHON_VERSION class TestCountryHolidays(unittest.TestCase): @@ -94,7 +93,7 @@ class TestAllInSameYear(unittest.TestCase): years = set(range(1950, 2051)) @pytest.mark.skipif( - sys.version_info < PYTHON_VERSION, + PYTHON_VERSION != PYTHON_LATEST_SUPPORTED_VERSION, reason="Run once on the latest Python version only", ) @mock.patch("pathlib.Path.rglob", return_value=()) @@ -117,7 +116,7 @@ def test_all_countries(self, unused_rglob_mock): self.assertEqual(self.years, country_holidays(country, years=self.years).years) @pytest.mark.skipif( - sys.version_info < PYTHON_VERSION, + PYTHON_VERSION != PYTHON_LATEST_SUPPORTED_VERSION, reason="Run once on the latest Python version only", ) @mock.patch("pathlib.Path.rglob", return_value=())