diff --git a/Changelog.md b/Changelog.md index 14093d0..51f4721 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,7 +2,7 @@ ## master (unreleased) -Nothing here yet. +- Making the Israel calendar more efficient (#498). ## v9.0.0 (2020-04-24) diff --git a/workalendar/asia/israel.py b/workalendar/asia/israel.py index c6c5eb0..59db5f5 100644 --- a/workalendar/asia/israel.py +++ b/workalendar/asia/israel.py @@ -1,5 +1,3 @@ -from datetime import date, timedelta - from pyluach.dates import GregorianDate, HebrewDate from ..core import Calendar, FRI, SAT @@ -15,64 +13,52 @@ class Israel(Calendar): def get_variable_days(self, year): days = super().get_variable_days(year) - delta = timedelta(days=1) - current_date = date(year, 1, 1) + hebrew_date = GregorianDate(year=year, month=1, day=1).to_heb() + jewish_year = hebrew_date.year - while current_date.year == year: - hebrew_date = GregorianDate( - year=current_date.year, - month=current_date.month, - day=current_date.day, - ).to_heb() - - jewish_year = hebrew_date.year - month = hebrew_date.month - day = hebrew_date.day - - if month == 7: - if day == 1: - days.append((current_date - delta, "Rosh Hashana Eve")) - days.append((current_date, "Rosh Hashana")) - days.append((current_date + delta, "Rosh Hashana")) - elif day == 10: - days.append((current_date - delta, "Yom Kippur Eve")) - days.append((current_date, "Yom Kippur")) - elif day == 15: - days.append((current_date - delta, "Sukkot Eve")) - days.append((current_date, "Sukkot")) - elif day == 22: - days.append((current_date - delta, "Shmini Atzeres Eve")) - days.append((current_date, "Shmini Atzeres")) - elif month == 1: - if day == 15: - days.append((current_date - delta, "Pesach Eve")) - days.append((current_date, "Pesach")) - elif day == 21: - days.append((current_date - delta, "7th of Pesach Eve")) - days.append((current_date, "7th of Pesach")) - elif month == 2: - if day == 5: - independence_date = current_date - if hebrew_date.weekday() == 6: - independence_date = HebrewDate( - jewish_year, month, 4 - ).to_pydate() - elif hebrew_date.weekday() == 7: - independence_date = HebrewDate( - jewish_year, month, 3 - ).to_pydate() - elif hebrew_date.weekday() == 2: - independence_date = HebrewDate( - jewish_year, month, 6 - ).to_pydate() - days.append( - (independence_date - delta, "Independence Day Eve") - ) - days.append((independence_date, "Independence Day")) - elif month == 3 and day == 6: - days.append((current_date - delta, "Shavout Eve")) - days.append((current_date, "Shavout")) - - current_date += delta + holidays_hebrew_dates = [ + (HebrewDate(jewish_year, 6, 29), "Rosh Hashana Eve"), + (HebrewDate(jewish_year + 1, 7, 1), "Rosh Hashana"), + (HebrewDate(jewish_year + 1, 7, 2), "Rosh Hashana"), + (HebrewDate(jewish_year + 1, 7, 9), "Yom Kippur Eve"), + (HebrewDate(jewish_year + 1, 7, 10), "Yom Kippur"), + (HebrewDate(jewish_year + 1, 7, 14), "Sukkot Eve"), + (HebrewDate(jewish_year + 1, 7, 15), "Sukkot"), + (HebrewDate(jewish_year + 1, 7, 21), "Shmini Atzeres Eve"), + (HebrewDate(jewish_year + 1, 7, 22), "Shmini Atzeres"), + (HebrewDate(jewish_year, 1, 14), "Pesach Eve"), + (HebrewDate(jewish_year, 1, 15), "Pesach"), + (HebrewDate(jewish_year, 1, 20), "7th of Pesach Eve"), + (HebrewDate(jewish_year, 1, 21), "7th of Pesach"), + (HebrewDate(jewish_year, 3, 5), "Shavout Eve"), + (HebrewDate(jewish_year, 3, 6), "Shavout"), + ] + holidays_hebrew_dates += self.get_hebrew_independence_day(jewish_year) + for holiday_hebrew_date, holiday_name in holidays_hebrew_dates: + days.append((holiday_hebrew_date.to_pydate(), holiday_name)) return days + + def get_hebrew_independence_day(self, jewish_year): + """ + Returns the independence day eve and independence day dates + according to the given hebrew year + + :param jewish_year: the specific hebrew year for calculating + the independence day dates + :return: independence day dates + in the type of List[Tuple[HebrewDate, str]] + """ + month = 2 + day = 5 + original_hebrew_independence_date = HebrewDate(jewish_year, month, day) + if original_hebrew_independence_date.weekday() == 6: + day = 4 + if original_hebrew_independence_date.weekday() == 7: + day = 3 + if original_hebrew_independence_date.weekday() == 2: + day = 6 + return [ + (HebrewDate(jewish_year, month, day - 1), "Independence Day Eve"), + (HebrewDate(jewish_year, month, day), "Independence Day") + ] diff --git a/workalendar/tests/test_asia.py b/workalendar/tests/test_asia.py index 2d967c2..0f3808b 100644 --- a/workalendar/tests/test_asia.py +++ b/workalendar/tests/test_asia.py @@ -1,5 +1,6 @@ from unittest.mock import patch from datetime import date +import time from . import GenericCalendarTest from ..asia import ( @@ -552,66 +553,73 @@ class IsraelTest(GenericCalendarTest): cal_class = Israel def test_holidays_2017(self): - holidays = self.cal.holidays_set(2017) - - self.assertIn(date(2017, 4, 11), holidays) # Passover (Pesach) - self.assertIn(date(2017, 4, 17), holidays) # Passover (Pesach) - self.assertIn( - date(2017, 5, 2), holidays - ) # Independence Day (Yom Ha-Atzmaut), was early in 2017 - self.assertIn(date(2017, 5, 31), holidays) # Shavuot - self.assertIn( - date(2017, 9, 21), holidays - ) # Jewish New Year (Rosh Ha-Shana) - self.assertIn( - date(2017, 9, 22), holidays - ) # Jewish New Year (Rosh Ha-Shana) - self.assertIn( - date(2017, 9, 30), holidays - ) # Yom Kippur (already a Saturday - Shabbat, weekend day) - self.assertIn(date(2017, 10, 5), holidays) # Sukkot - self.assertIn(date(2017, 10, 12), holidays) # Sukkot + calculated_holidays = self.cal.holidays_set(2017) + known_holidays = { + date(2017, 4, 10), # Passover (Pesach) + date(2017, 4, 11), + date(2017, 4, 16), + date(2017, 4, 17), + date(2017, 5, 1), # Independence Day (Yom Ha-Atzmaut) + date(2017, 5, 2), + date(2017, 9, 20), # Jewish New Year (Rosh Ha-Shana) + date(2017, 9, 21), + date(2017, 9, 22), + date(2017, 9, 29), # Yom Kippur + date(2017, 9, 30), + date(2017, 10, 4), # Sukkot + date(2017, 10, 5), + date(2017, 10, 11), + date(2017, 10, 12), + date(2017, 5, 30), # Shavuot + date(2017, 5, 31), + } + self.assertEqual(calculated_holidays, known_holidays) def test_holidays_2018(self): - holidays = self.cal.holidays_set(2018) - - self.assertIn(date(2018, 3, 31), holidays) # Passover (Pesach) - self.assertIn(date(2018, 4, 6), holidays) # Passover (Pesach) - self.assertIn( - date(2018, 4, 19), holidays - ) # Independence Day (Yom Ha-Atzmaut), was delayed in 2018 - self.assertIn(date(2018, 5, 20), holidays) # Shavuot - self.assertIn( - date(2018, 9, 10), holidays - ) # Jewish New Year (Rosh Ha-Shana) - self.assertIn( - date(2018, 9, 11), holidays - ) # Jewish New Year (Rosh Ha-Shana) - self.assertIn(date(2018, 9, 19), holidays) # Yom Kippur - self.assertIn(date(2018, 9, 24), holidays) # Sukkot - self.assertIn(date(2018, 9, 30), holidays) # Sukkot + calculated_holidays = self.cal.holidays_set(2018) + known_holidays = { + date(2018, 3, 30), # Passover (Pesach) + date(2018, 3, 31), + date(2018, 4, 5), + date(2018, 4, 6), + date(2018, 4, 18), # Independence Day (Yom Ha-Atzmaut) + date(2018, 4, 19), + date(2018, 9, 9), # Rosh Hashana + date(2018, 9, 10), + date(2018, 9, 11), + date(2018, 9, 18), # Yom Kippur + date(2018, 9, 19), + date(2018, 9, 23), # Sukkot + date(2018, 9, 24), + date(2018, 9, 30), + date(2018, 10, 1), + date(2018, 5, 19), # Shavuot + date(2018, 5, 20), + } + self.assertEqual(calculated_holidays, known_holidays) def test_holidays_2019(self): - holidays = self.cal.holidays_set(2019) - - self.assertIn(date(2019, 4, 20), holidays) # Passover (Pesach) - self.assertIn(date(2019, 4, 26), holidays) # Passover (Pesach) - self.assertIn( - date(2019, 5, 9), holidays - ) # Independence Day (Yom Ha-Atzmaut), was delayed in 2019 - self.assertIn(date(2019, 6, 9), holidays) # Shavuot - self.assertIn( - date(2019, 9, 29), holidays - ) # Jewish New Year (Rosh Ha-Shana) - self.assertIn( - date(2019, 9, 30), holidays - ) # Jewish New Year (Rosh Ha-Shana) - self.assertIn( - date(2019, 10, 1), holidays - ) # Jewish New Year (Rosh Ha-Shana) - self.assertIn(date(2019, 10, 9), holidays) # Yom Kippur - self.assertIn(date(2019, 10, 14), holidays) # Sukkot - self.assertIn(date(2019, 10, 20), holidays) # Sukkot + calculated_holidays = self.cal.holidays_set(2019) + known_holidays = { + date(2019, 4, 19), # Passover (Pesach) + date(2019, 4, 20), # Passover (Pesach) + date(2019, 4, 25), # Passover (Pesach) + date(2019, 4, 26), # Passover (Pesach) + date(2019, 5, 8), # Independence Day (Yom Ha-Atzmaut) + date(2019, 5, 9), # Independence Day (Yom Ha-Atzmaut) + date(2019, 6, 8), # Shavuot + date(2019, 6, 9), # Shavuot + date(2019, 9, 29), # Rosh Hashana + date(2019, 9, 30), # Rosh Hashana + date(2019, 10, 1), # Rosh Hashana + date(2019, 10, 8), # Yom Kippur + date(2019, 10, 9), # Yom Kippur + date(2019, 10, 13), # Sukkot + date(2019, 10, 14), # Sukkot + date(2019, 10, 20), # Sukkot + date(2019, 10, 21), # Sukkot + } + self.assertEqual(calculated_holidays, known_holidays) def test_holidays_2020(self): calculated_holidays = self.cal.holidays_set(2020) @@ -635,3 +643,16 @@ class IsraelTest(GenericCalendarTest): date(2020, 5, 29), # Shavuot } self.assertEqual(calculated_holidays, known_holidays) + + def test_is_holiday_performance(self): + random_date = date(2019, 10, 9) + japan_cal = Japan() + timer = time.time() + for i in range(30): + japan_cal.is_holiday(random_date) + japan_time = time.time() - timer + timer = time.time() + for i in range(30): + self.cal.is_holiday(random_date) + israel_time = time.time() - timer + self.assertGreater(japan_time * 3, israel_time)