diff --git a/holidays/groups/custom.py b/holidays/groups/custom.py index dd54b26d5..2120aa1f1 100644 --- a/holidays/groups/custom.py +++ b/holidays/groups/custom.py @@ -10,6 +10,10 @@ # Website: https://github.com/vacanza/holidays # License: MIT (see LICENSE file) +from datetime import date + +from holidays.helpers import _normalize_tuple + class StaticHolidays: """Helper class for special and substituted holidays support. @@ -33,3 +37,11 @@ def __init__(self, cls) -> None: ): setattr(self, attribute_name, value) self.has_substituted_holidays = True + + # Populate substituted holidays from adjacent years. + self.weekend_workdays = set() + for special_public_holidays in getattr(self, "special_public_holidays", {}).values(): + for special_public_holiday in _normalize_tuple(special_public_holidays): + if len(special_public_holiday) == 5: # The fifth element is the year. + _, _, from_month, from_day, from_year = special_public_holiday + self.weekend_workdays.add(date(from_year, from_month, from_day)) diff --git a/holidays/holiday_base.py b/holidays/holiday_base.py index 052a4d137..2db65448c 100644 --- a/holidays/holiday_base.py +++ b/holidays/holiday_base.py @@ -233,7 +233,7 @@ def _populate(self, year): ones.""" weekend: set[int] = {SAT, SUN} """Country weekend days.""" - weekend_workdays: set[date] = set() + weekend_workdays: set[date] """Working days moved to weekends.""" default_category: str = PUBLIC """The entity category used by default.""" @@ -362,7 +362,7 @@ def __init__( self.language = language.lower() if language else None self.observed = observed self.subdiv = subdiv - self.weekend_workdays = set() + self.weekend_workdays = getattr(self, "weekend_workdays", set()) supported_languages = set(self.supported_languages) self.tr = ( diff --git a/tests/countries/test_azerbaijan.py b/tests/countries/test_azerbaijan.py index 462b1359e..69da67629 100644 --- a/tests/countries/test_azerbaijan.py +++ b/tests/countries/test_azerbaijan.py @@ -66,6 +66,26 @@ def test_substituted_holidays(self): "2025-01-03", ) + for year, dts in { + 2012: ( + "2012-12-29", + "2012-12-30", + ), + 2013: ( + "2013-12-28", + "2013-12-29", + ), + 2019: ( + "2019-12-28", + "2019-12-29", + ), + 2023: ("2023-12-30",), + 2024: ("2024-12-29",), + }.items(): + az_holidays = Azerbaijan(years=year) + for dt in dts: + self.assertTrue(az_holidays.is_working_day(dt)) + def test_new_years_day(self): name = "Yeni il bayramı" self.assertHolidayName(name, (f"{year}-01-01" for year in range(1990, 2050))) diff --git a/tests/countries/test_belarus.py b/tests/countries/test_belarus.py index 3fe4dfe82..efabbcc8d 100644 --- a/tests/countries/test_belarus.py +++ b/tests/countries/test_belarus.py @@ -225,6 +225,18 @@ def test_radunitsa(self): "2030-05-07", ) + for year, dts in { + 2006: ( + "2006-01-21", + "2006-05-06", + "2006-11-04", + "2006-12-30", + ), + }.items(): + be_holidays = Belarus(years=year) + for dt in dts: + self.assertTrue(be_holidays.is_working_day(dt)) + def test_dzyady(self): name = "Дзень памяці" diff --git a/tests/countries/test_china.py b/tests/countries/test_china.py index 35f2ee4ef..d24ba1472 100644 --- a/tests/countries/test_china.py +++ b/tests/countries/test_china.py @@ -29,6 +29,50 @@ def test_no_holidays(self): self.assertNoHolidays(China(years=1949)) self.assertNoHolidays(China(years=1949, categories=HALF_DAY)) + def test_substituted_holidays(self): + for year, dts in { + 2001: ( + "2001-01-20", + "2001-01-21", + "2001-04-28", + "2001-04-29", + "2001-09-29", + "2001-09-30", + "2001-12-29", + "2001-12-30", + ), + 2005: ( + "2005-02-05", + "2005-02-06", + "2005-04-30", + "2005-05-08", + "2005-10-08", + "2005-10-09", + "2005-12-31", + ), + 2006: ( + "2006-01-28", + "2006-02-05", + "2006-04-29", + "2006-04-30", + "2006-09-30", + "2006-10-08", + "2006-12-30", + "2006-12-31", + ), + 2011: ( + "2011-01-30", + "2011-02-12", + "2011-04-02", + "2011-10-08", + "2011-10-09", + "2011-12-31", + ), + }.items(): + cn_holidays = China(years=year) + for dt in dts: + self.assertTrue(cn_holidays.is_working_day(dt)) + def test_new_years_day(self): self.assertHolidayName("元旦", (f"{year}-01-01" for year in range(1950, 2050))) diff --git a/tests/countries/test_kazakhstan.py b/tests/countries/test_kazakhstan.py index 1567cc1a6..4b54ab1ba 100644 --- a/tests/countries/test_kazakhstan.py +++ b/tests/countries/test_kazakhstan.py @@ -242,6 +242,17 @@ def test_substituted_holidays(self): "2025-01-03", ) + for year, dts in { + 2013: ( + "2013-05-04", + "2013-10-12", + "2013-12-28", + ), + }.items(): + kz_holidays = Kazakhstan(years=year) + for dt in dts: + self.assertTrue(kz_holidays.is_working_day(dt)) + def test2022(self): self.assertHolidays( Kazakhstan(years=2022), diff --git a/tests/countries/test_taiwan.py b/tests/countries/test_taiwan.py index 515741d0d..72ba77097 100644 --- a/tests/countries/test_taiwan.py +++ b/tests/countries/test_taiwan.py @@ -28,6 +28,14 @@ def test_country_aliases(self): def test_no_holidays(self): self.assertNoHolidays(Taiwan(years=1911)) + def test_substituted_holidays(self): + for year, dts in { + 2014: ("2014-12-27",), + }.items(): + tw_holidays = Taiwan(years=year) + for dt in dts: + self.assertTrue(tw_holidays.is_working_day(dt)) + def test_new_years_day(self): name = "中華民國開國紀念日" self.assertHolidayName(name, (f"{year}-01-01" for year in range(1990, 2030))) diff --git a/tests/countries/test_ukraine.py b/tests/countries/test_ukraine.py index 630b31bd3..2d64387c4 100644 --- a/tests/countries/test_ukraine.py +++ b/tests/countries/test_ukraine.py @@ -33,6 +33,18 @@ def test_no_holidays(self): def test_special_holidays(self): self.assertHoliday("1995-01-09") + def test_substituted_holidays(self): + for year, dts in { + 1996: ( + "1996-05-05", + "1996-05-12", + "1996-12-28", + ), + }.items(): + ua_holidays = Ukraine(years=year) + for dt in dts: + self.assertTrue(ua_holidays.is_working_day(dt)) + def test_new_year_day(self): self.assertHoliday(f"{year}-01-01" for year in range(1991, 2023)) dt = ( diff --git a/tests/countries/test_vietnam.py b/tests/countries/test_vietnam.py index 38e74235a..00c420fce 100644 --- a/tests/countries/test_vietnam.py +++ b/tests/countries/test_vietnam.py @@ -174,6 +174,18 @@ def test_substituted_holidays(self): "2024-04-29", ) + for year, dts in { + 2014: ( + "2014-04-26", + "2014-09-06", + "2014-12-27", + ), + 2019: ("2019-01-05",), + }.items(): + vn_holidays = Vietnam(years=year) + for dt in dts: + self.assertTrue(vn_holidays.is_working_day(dt)) + def test_l10n_default(self): self.assertLocalizedHolidays( ("2022-01-01", "Tết Dương lịch"),