diff --git a/holidays/calendars/hebrew.py b/holidays/calendars/hebrew.py index b7f39cee3..b55811ed2 100644 --- a/holidays/calendars/hebrew.py +++ b/holidays/calendars/hebrew.py @@ -1598,7 +1598,36 @@ class _HebrewLunisolar: 2100: (OCT, 13), } - @staticmethod - def _get_holiday(holiday: str, year: int) -> Optional[date]: - dt = getattr(_HebrewLunisolar, f"{holiday}_DATES", {}).get(year, ()) + def _get_holiday(self, holiday: str, year: int) -> Optional[date]: + dt = getattr(self, f"{holiday}_DATES", {}).get(year, ()) return date(year, *dt) if dt else None + + def hanukkah_date(self, year: int) -> set[Optional[date]]: + return {self._get_holiday(HANUKKAH, y) for y in (year - 1, year)} + + def israel_independence_date(self, year: int) -> Optional[date]: + return self._get_holiday(INDEPENDENCE_DAY, year) + + def lag_baomer_date(self, year: int) -> Optional[date]: + return self._get_holiday(LAG_BAOMER, year) + + def passover_date(self, year: int) -> Optional[date]: + return self._get_holiday(PASSOVER, year) + + def purim_date(self, year: int) -> Optional[date]: + return self._get_holiday(PURIM, year) + + def rosh_hashanah_date(self, year: int) -> Optional[date]: + return self._get_holiday(ROSH_HASHANAH, year) + + def shavuot_date(self, year: int) -> Optional[date]: + return self._get_holiday(SHAVUOT, year) + + def sukkot_date(self, year: int) -> Optional[date]: + return self._get_holiday(SUKKOT, year) + + def tisha_bav_date(self, year: int) -> Optional[date]: + return self._get_holiday(TISHA_BAV, year) + + def yom_kippur_date(self, year: int) -> Optional[date]: + return self._get_holiday(YOM_KIPPUR, year) diff --git a/holidays/countries/israel.py b/holidays/countries/israel.py index 283eff879..836e6cc03 100644 --- a/holidays/countries/israel.py +++ b/holidays/countries/israel.py @@ -12,20 +12,9 @@ from gettext import gettext as tr -from holidays.calendars import _HebrewLunisolar from holidays.calendars.gregorian import _timedelta, FRI, SAT -from holidays.calendars.hebrew import ( - HANUKKAH, - INDEPENDENCE_DAY, - LAG_BAOMER, - PASSOVER, - PURIM, - ROSH_HASHANAH, - SHAVUOT, - SUKKOT, - YOM_KIPPUR, -) from holidays.constants import OPTIONAL, PUBLIC, SCHOOL +from holidays.groups import HebrewCalendarHolidays from holidays.observed_holiday_base import ( ObservedHolidayBase, MON_TO_NEXT_TUE, @@ -38,7 +27,7 @@ ) -class Israel(ObservedHolidayBase): +class Israel(ObservedHolidayBase, HebrewCalendarHolidays): """ Israel holidays. @@ -57,117 +46,103 @@ class Israel(ObservedHolidayBase): start_year = 1948 def __init__(self, *args, **kwargs): + HebrewCalendarHolidays.__init__(self) kwargs.setdefault("observed_rule", FRI_TO_PREV_THU + SAT_TO_PREV_THU) super().__init__(*args, **kwargs) - def _get_holiday(self, holiday: str): - return _HebrewLunisolar._get_holiday(holiday, self._year) + def _add_observed(self, dt, name, rule): + is_observed, _ = super()._add_observed(dt, name, rule) + if not is_observed: + self._add_holiday(name, dt) def _populate_public_holidays(self): # Rosh Hashanah (New Year). - name = tr("ראש השנה") - rosh_hashanah_dt = self._get_holiday(ROSH_HASHANAH) - self._add_holiday(name, rosh_hashanah_dt) - self._add_holiday(name, _timedelta(rosh_hashanah_dt, +1)) + self._add_rosh_hashanah(tr("ראש השנה"), range(2)) # Yom Kippur (Day of Atonement). - self._add_holiday(tr("יום כיפור"), self._get_holiday(YOM_KIPPUR)) + self._add_yom_kippur(tr("יום כיפור")) - sukkot_dt = self._get_holiday(SUKKOT) # Sukkot (Feast of Tabernacles). - self._add_holiday(tr("סוכות"), sukkot_dt) + self._add_sukkot(tr("סוכות")) # Simchat Torah / Shemini Atzeret. - self._add_holiday(tr("שמחת תורה/שמיני עצרת"), _timedelta(sukkot_dt, +7)) + self._add_sukkot(tr("שמחת תורה/שמיני עצרת"), +7) - passover_dt = self._get_holiday(PASSOVER) # Pesach (Passover). - self._add_holiday(tr("פסח"), passover_dt) + self._add_passover(tr("פסח")) # Shvi'i shel Pesach (Seventh day of Passover) - self._add_holiday(tr("שביעי של פסח"), _timedelta(passover_dt, +6)) + self._add_passover(tr("שביעי של פסח"), +6) - # Yom Ha-Atzmaut (Independence Day). - name = tr("יום העצמאות") - independence_day_dt = self._get_holiday(INDEPENDENCE_DAY) rule = FRI_TO_PREV_THU + SAT_TO_PREV_THU if self._year >= 2004: rule += MON_TO_NEXT_TUE - is_observed, _ = self._add_observed(independence_day_dt, name, rule) - if not is_observed: - self._add_holiday(name, independence_day_dt) + self._add_observed( + self._hebrew_calendar.israel_independence_date(self._year), + # Yom Ha-Atzmaut (Independence Day). + tr("יום העצמאות"), + rule, + ) # Shavuot. - self._add_holiday(tr("שבועות"), self._get_holiday(SHAVUOT)) + self._add_shavuot(tr("שבועות")) def _populate_optional_holidays(self): - sukkot_dt = self._get_holiday(SUKKOT) - for offset in range(1, 6): - # Chol HaMoed Sukkot (Feast of Tabernacles holiday). - self._add_holiday(tr("חול המועד סוכות"), _timedelta(sukkot_dt, offset)) + # Chol HaMoed Sukkot (Feast of Tabernacles holiday). + self._add_sukkot(tr("חול המועד סוכות"), range(1, 6)) if self._year >= 2008: # Sigd. - self._add_holiday(tr("סיגד"), _timedelta(self._get_holiday(YOM_KIPPUR), +49)) + self._add_yom_kippur(tr("סיגד"), +49) # Purim. - self._add_holiday(tr("פורים"), self._get_holiday(PURIM)) + self._add_purim(tr("פורים")) - passover_dt = self._get_holiday(PASSOVER) - for offset in range(1, 6): - # Chol HaMoed Pesach (Passover holiday). - self._add_holiday(tr("חול המועד פסח"), _timedelta(passover_dt, offset)) + # Chol HaMoed Pesach (Passover holiday). + self._add_passover(tr("חול המועד פסח"), range(1, 6)) if self._year >= 1963: - # Yom Hazikaron (Fallen Soldiers and Victims of Terrorism Remembrance Day). - name = tr("יום הזיכרון לחללי מערכות ישראל ונפגעי פעולות האיבה") - remembrance_day_dt = _timedelta(self._get_holiday(INDEPENDENCE_DAY), -1) rule = THU_TO_PREV_WED + FRI_TO_PREV_WED if self._year >= 2004: rule += SUN_TO_NEXT_MON - is_observed, _ = self._add_observed(remembrance_day_dt, name, rule) - if not is_observed: - self._add_holiday(name, remembrance_day_dt) + self._add_observed( + _timedelta(self._hebrew_calendar.israel_independence_date(self._year), -1), + # Yom Hazikaron (Fallen Soldiers and Victims of Terrorism Remembrance Day). + tr("יום הזיכרון לחללי מערכות ישראל ונפגעי פעולות האיבה"), + rule, + ) if self._year >= 1998: # Yom Yerushalayim (Jerusalem Day). - self._add_holiday(tr("יום ירושלים"), _timedelta(self._get_holiday(LAG_BAOMER), +10)) + self._add_lag_baomer(tr("יום ירושלים"), +10) - # Tisha B'Av (Tisha B'Av, fast). - name = tr("תשעה באב") - tisha_bav_dt = self._get_holiday("TISHA_BAV") - is_observed, _ = self._add_observed(tisha_bav_dt, name, SAT_TO_NEXT_SUN) - if not is_observed: - self._add_holiday(name, tisha_bav_dt) + self._add_observed( + self._hebrew_calendar.tisha_bav_date(self._year), + # Tisha B'Av (Tisha B'Av, fast). + tr("תשעה באב"), + SAT_TO_NEXT_SUN, + ) def _populate_school_holidays(self): - sukkot_dt = self._get_holiday(SUKKOT) - for offset in range(1, 6): - # Chol HaMoed Sukkot (Feast of Tabernacles holiday). - self._add_holiday(tr("חול המועד סוכות"), _timedelta(sukkot_dt, offset)) - - for year in (self._year - 1, self._year): - hanukkah_dt = _HebrewLunisolar._get_holiday(HANUKKAH, year) - for offset in range(8): - # Hanukkah. - self._add_holiday(tr("חנוכה"), _timedelta(hanukkah_dt, offset)) - - # Ta`anit Ester (Fast of Esther). - name = tr("תענית אסתר") - purim_dt = self._get_holiday(PURIM) - taanit_ester_dt = _timedelta(purim_dt, -1) - is_observed, _ = self._add_observed(taanit_ester_dt, name, SAT_TO_PREV_THU) - if not is_observed: - self._add_holiday(name, taanit_ester_dt) + # Chol HaMoed Sukkot (Feast of Tabernacles holiday). + self._add_sukkot(tr("חול המועד סוכות"), range(1, 6)) + + # Hanukkah. + self._add_hanukkah(tr("חנוכה"), range(8)) + + self._add_observed( + _timedelta(self._hebrew_calendar.purim_date(self._year), -1), + # Ta`anit Ester (Fast of Esther). + tr("תענית אסתר"), + SAT_TO_PREV_THU, + ) # Purim. - self._add_holiday(tr("פורים"), purim_dt) + self._add_purim(tr("פורים")) - passover_dt = self._get_holiday(PASSOVER) - for offset in range(1, 6): - # Chol HaMoed Pesach (Passover holiday). - self._add_holiday(tr("חול המועד פסח"), _timedelta(passover_dt, offset)) + # Chol HaMoed Pesach (Passover holiday). + self._add_passover(tr("חול המועד פסח"), range(1, 6)) # Lag Ba'omer (Lag BaOmer). - self._add_holiday(tr('ל"ג בעומר'), self._get_holiday(LAG_BAOMER)) + self._add_lag_baomer(tr('ל"ג בעומר')) class IL(Israel): diff --git a/holidays/groups/__init__.py b/holidays/groups/__init__.py index a825b59e0..ef5527cfc 100644 --- a/holidays/groups/__init__.py +++ b/holidays/groups/__init__.py @@ -17,6 +17,7 @@ from holidays.groups.christian import ChristianHolidays from holidays.groups.custom import StaticHolidays from holidays.groups.eastern import EasternCalendarHolidays +from holidays.groups.hebrew import HebrewCalendarHolidays from holidays.groups.hindu import HinduCalendarHolidays from holidays.groups.international import InternationalHolidays from holidays.groups.islamic import IslamicHolidays diff --git a/holidays/groups/hebrew.py b/holidays/groups/hebrew.py new file mode 100644 index 000000000..73170503c --- /dev/null +++ b/holidays/groups/hebrew.py @@ -0,0 +1,151 @@ +# 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: Vacanza Team and individual contributors (see AUTHORS file) +# dr-prodigy (c) 2017-2023 +# ryanss (c) 2014-2017 +# Website: https://github.com/vacanza/holidays +# License: MIT (see LICENSE file) + +from collections.abc import Iterable +from datetime import date +from typing import Optional, Union + +from holidays.calendars import _HebrewLunisolar +from holidays.calendars.gregorian import _timedelta + + +class HebrewCalendarHolidays: + """ + Hebrew lunisolar calendar holidays. + """ + + def __init__(self) -> None: + self._hebrew_calendar = _HebrewLunisolar() + + def _add_hebrew_calendar_holiday( + self, name: str, hol_date: date, days_delta: Union[int, Iterable[int]] = 0 + ) -> set[date]: + added_dates = set() + for delta in (days_delta,) if isinstance(days_delta, int) else days_delta: + if dt := self._add_holiday(name, _timedelta(hol_date, delta)): + added_dates.add(dt) + return added_dates + + def _add_hanukkah( + self, name: str, days_delta: Union[int, Iterable[int]] = 0 + ) -> set[Optional[date]]: + """ + Add Hanukkah. + In some Gregorian years, there may be two Hanukkah dates. + + Hanukkah is a Jewish festival commemorating the recovery of Jerusalem + and subsequent rededication of the Second Temple. + https://en.wikipedia.org/wiki/Hanukkah + """ + dts = self._hebrew_calendar.hanukkah_date(self._year) + for dt in dts: + self._add_hebrew_calendar_holiday(name, dt, days_delta) # type: ignore[arg-type] + return dts + + def _add_lag_baomer(self, name: str, days_delta: Union[int, Iterable[int]] = 0) -> set[date]: + """ + Add Lag BaOmer. + + Lag BaOmer, also Lag B'Omer or Lag LaOmer, is a Jewish religious holiday celebrated + on the 33rd day of the Counting of the Omer, which occurs on the 18th day of + the Hebrew month of Iyar. + https://en.wikipedia.org/wiki/Lag_BaOmer + """ + return self._add_hebrew_calendar_holiday( + name, + self._hebrew_calendar.lag_baomer_date(self._year), # type: ignore[arg-type] + days_delta, + ) + + def _add_passover(self, name: str, days_delta: Union[int, Iterable[int]] = 0) -> set[date]: + """ + Add Passover. + + Passover, also called Pesach, is a major Jewish holiday and one of the Three Pilgrimage + Festivals. It celebrates the Exodus of the Israelites from slavery in Egypt. + https://en.wikipedia.org/wiki/Passover + """ + return self._add_hebrew_calendar_holiday( + name, + self._hebrew_calendar.passover_date(self._year), # type: ignore[arg-type] + days_delta, + ) + + def _add_purim(self, name: str) -> set[date]: + """ + Add Purim. + + Purim is a Jewish holiday that commemorates the saving of the Jewish people + from annihilation at the hands of an official of the Achaemenid Empire named Haman, + as it is recounted in the Book of Esther. + https://en.wikipedia.org/wiki/Purim + """ + return self._add_hebrew_calendar_holiday( + name, + self._hebrew_calendar.purim_date(self._year), # type: ignore[arg-type] + ) + + def _add_rosh_hashanah( + self, name: str, days_delta: Union[int, Iterable[int]] = 0 + ) -> set[date]: + """ + Add Rosh Hashanah. + + Rosh Hashanah is the New Year in Judaism. + https://en.wikipedia.org/wiki/Rosh_Hashanah + """ + return self._add_hebrew_calendar_holiday( + name, + self._hebrew_calendar.rosh_hashanah_date(self._year), # type: ignore[arg-type] + days_delta, + ) + + def _add_shavuot(self, name: str) -> set[date]: + """ + Add Shavuot. + + Shavuot, or Shvues, is a Jewish holiday, one of the biblically ordained + Three Pilgrimage Festivals. It occurs on the sixth day of the Hebrew month of Sivan. + https://en.wikipedia.org/wiki/Shavuot + """ + return self._add_hebrew_calendar_holiday( + name, + self._hebrew_calendar.shavuot_date(self._year), # type: ignore[arg-type] + ) + + def _add_sukkot(self, name: str, days_delta: Union[int, Iterable[int]] = 0) -> set[date]: + """ + Add Sukkot. + + Sukkot, also known as the Feast of Tabernacles or Feast of Booths, is a Torah-commanded + holiday celebrated for seven days, beginning on the 15th day of the month of Tishrei. + https://en.wikipedia.org/wiki/Sukkot + """ + return self._add_hebrew_calendar_holiday( + name, + self._hebrew_calendar.sukkot_date(self._year), # type: ignore[arg-type] + days_delta, + ) + + def _add_yom_kippur(self, name: str, days_delta: Union[int, Iterable[int]] = 0) -> set[date]: + """ + Add Yom Kippur. + + Yom Kippur (Day of Atonement) is the holiest day of the year in Judaism. + It occurs annually on the 10th of Tishrei. + https://en.wikipedia.org/wiki/Yom_Kippur + """ + return self._add_hebrew_calendar_holiday( + name, + self._hebrew_calendar.yom_kippur_date(self._year), # type: ignore[arg-type] + days_delta, + )