Repository: peopledoc/workalendar
Pull request #593 (2020-11-20 11:14:07)

Add Russia COVID-19 2020 non-working days
refs #578


- [x] Tests with a significant number of years to be tested for your calendar.
- [x] Changelog amended with a mention describing your changes. **Note** *Please do NOT change the version number here. It's the project maintainers' duty.*



Patch:
diff --git a/Changelog.md b/Changelog.md
index 3100d28..3c5f221 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -4,6 +4,8 @@
 
 - Fix Russia calendar: non-working days are shifted to the next MON when they happen on the week-end (#589).
 - Fix Russia New year holidays. It has become a week off since 2005 (related to #578).
+- Added a `daterange` function in `workalendar.core` module to iterate between two dates.
+- Added Russia COVID-19 non-working days for the year 2020 (#578).
 
 ## v13.0.0 (2020-11-13)
 
diff --git a/workalendar/core.py b/workalendar/core.py
index 87348c7..5171f3a 100644
--- a/workalendar/core.py
+++ b/workalendar/core.py
@@ -48,6 +48,21 @@ def cleaned_date(day, keep_datetime=False):
     return day
 
 
+def daterange(start, end):
+    """
+    Yield days from ``start`` to ``end`` including both of them.
+
+    If start and end are in opposite order, they'll be swapped silently.
+    """
+    # Swap if necessary
+    if start > end:
+        end, start = start, end
+    day = start
+    while day <= end:
+        yield day
+        day += timedelta(days=1)
+
+
 class ChristianMixin:
     EASTER_METHOD = None  # to be assigned in the inherited mixin
     include_epiphany = False
diff --git a/workalendar/europe/russia.py b/workalendar/europe/russia.py
index 2314c17..2b639be 100644
--- a/workalendar/europe/russia.py
+++ b/workalendar/europe/russia.py
@@ -1,6 +1,6 @@
 from datetime import date
 
-from ..core import OrthodoxCalendar, MON
+from ..core import OrthodoxCalendar, MON, daterange
 from ..registry_tools import iso_register
 
 
@@ -32,6 +32,13 @@ class Russia(OrthodoxCalendar):
                 (date(year, 1, 8), "Eighth Day after New Year"),
             ])
 
+        if year == 2020:
+            index = 1
+            for day in daterange(date(year, 3, 28), date(year, 4, 30)):
+                days.append(
+                    (day, f"Non-Working Day (COVID-19) #{index}")
+                )
+                index += 1
         return days
 
     def get_calendar_holidays(self, year):


Test patch:
diff --git a/workalendar/tests/test_core.py b/workalendar/tests/test_core.py
index 5f9bb6a..5d71d94 100644
--- a/workalendar/tests/test_core.py
+++ b/workalendar/tests/test_core.py
@@ -9,7 +9,8 @@ from . import CoreCalendarTest
 from ..core import (
     MON, TUE, THU, FRI, WED, SAT, SUN,
     Calendar, LunarMixin, WesternCalendar,
-    CalverterMixin, IslamicMixin, JalaliMixin
+    CalverterMixin, IslamicMixin, JalaliMixin,
+    daterange,
 )
 from ..exceptions import UnsupportedDateType, CalendarError
 
@@ -775,3 +776,46 @@ class FatTuesdayLabelTest(TestCase):
         cal = MockCalendarNoFatTuesdayLabel()
         with self.assertRaises(CalendarError):
             cal.get_fat_tuesday(2020)
+
+
+def test_daterange_start_end():
+    start = date(2020, 4, 1)
+    end = date(2020, 4, 10)
+    date_list = list(daterange(start, end))
+    assert date_list == [
+        date(2020, 4, 1),
+        date(2020, 4, 2),
+        date(2020, 4, 3),
+        date(2020, 4, 4),
+        date(2020, 4, 5),
+        date(2020, 4, 6),
+        date(2020, 4, 7),
+        date(2020, 4, 8),
+        date(2020, 4, 9),
+        date(2020, 4, 10),
+    ]
+
+
+def test_daterange_end_start():
+    end = date(2020, 4, 1)
+    start = date(2020, 4, 10)
+    date_list = list(daterange(start, end))
+    assert date_list == [
+        date(2020, 4, 1),
+        date(2020, 4, 2),
+        date(2020, 4, 3),
+        date(2020, 4, 4),
+        date(2020, 4, 5),
+        date(2020, 4, 6),
+        date(2020, 4, 7),
+        date(2020, 4, 8),
+        date(2020, 4, 9),
+        date(2020, 4, 10),
+    ]
+
+
+def test_daterange_same_date():
+    # Stupid usecase, but nonetheless
+    start = end = date(2020, 4, 1)
+    date_list = list(daterange(start, end))
+    assert date_list == [date(2020, 4, 1)]
diff --git a/workalendar/tests/test_europe.py b/workalendar/tests/test_europe.py
index 1dab571..a528e1f 100644
--- a/workalendar/tests/test_europe.py
+++ b/workalendar/tests/test_europe.py
@@ -2,6 +2,7 @@ from datetime import date, timedelta
 from collections import Counter
 
 from . import GenericCalendarTest
+from ..core import daterange
 from ..europe import (
     Austria,
     Bulgaria,
@@ -1437,6 +1438,22 @@ class RussiaTest(GenericCalendarTest):
             "Victory Day shift"
         )
 
+    def test_covid19_2020(self):
+        # By decree, several days of March and April were defined
+        # as non-working days because of the COVID-19 crisis.
+        # It spans from March 28th to April 30th (included).
+        holidays = self.cal.holidays_set(2020)
+        start = date(2020, 3, 28)
+        end = date(2020, 4, 30)
+        for day in daterange(start, end):
+            self.assertIn(day, holidays)
+        # Not for 2019, though
+        holidays = self.cal.holidays_set(2019)
+        start = date(2019, 3, 28)
+        end = date(2019, 4, 30)
+        for day in daterange(start, end):
+            self.assertNotIn(day, holidays)
+
     def test_new_year_holidays_2004(self):
         # At that time, only Jan 1st/2nd were holidays.
         holidays = self.cal.holidays_set(2004)