Repository: peopledoc/workalendar
Pull request #379 (2019-06-28 06:32:40)

Add JapanBank class
refs #369 

This PR attempts to create a new calendar, JapanBank that inherits from Japan. The [Bank of Japan
publicly lists their official holidays](https://www.boj.or.jp/en/about/outline/holi.htm/).
In addition, due to the change in emperor in 2019, there were some additional fixed holidays added that
year and some of the [variable holidays for 2020](https://www.timeanddate.com/holidays/japan/) were shifted around. 

- [x] Tests with a significant number of years to be tested for your calendar.
- [x] Docstrings for the Calendar class and specific methods.
- [ ] Use the ``workalendar.registry_tools.iso_register`` decorator to register your new calendar using ISO codes (optional).
- [x] Calendar country / label added to the README.rst file,
- [x] Changelog amended with a mention like: "Added ``<country>`` by ``@pseudo`` (#)"

<!-- if your contribution is a fix -->

- [x] Tests with a significant number of years to be tested for your calendar.
- [x] Changelog amended with a mention describing your changes.

<!-- Release management

- Commit for the tag:
    - [ ] Edit version in setup.py
    - [ ] Add version in Changelog.md ; trim things
    - [ ] Push & wait for the tests to be green
    - [ ] tag me.
    - [ ] build sdist package
- Back to dev commit:
    - [ ] Edit version in setup.py
    - [ ] Add the "master / nothing to see here" in Changelog.md
    - [ ] Push & wait for the tests to be green
- [ ] Merge --ff
- Github stuff
    - [ ] Push tag in Github
    - [ ] Edit release on Github using the changelog.
    - [ ] Delete branch
- [ ] upload release on PyPI
- [ ] (*optional*) Make feeback on the various PR or issues.

 -->


raybuhr: > Apart from the changelog bit, I think you have brought a great contribution here!
> You also have a flake8 error but that should be easy to fix.
> All you'll have to do would be to edit the changelog a bit, squash all your commits into one, and we'll be fine.

@brunobord I made the requested changes. Do you want me to squash all commits first or can you just do a squash and merge?

Patch:
diff --git a/Changelog.md b/Changelog.md
index 48a0330..026591e 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,7 +2,11 @@
 
 ## master (unreleased)
 
-Nothing to see here yet.
+- Added adjustments to 2019-2020 Japan calendar due to the coronation of a new emperor.
+
+### New Calendar
+
+- Added JapanBank by @raybuhr (#379)
 
 ## v5.1.1 (2019-06-27)
 
diff --git a/README.rst b/README.rst
index b418aed..b54d363 100644
--- a/README.rst
+++ b/README.rst
@@ -145,6 +145,7 @@ Asia
 * Hong Kong
 * Israel
 * Japan
+* JapanBank
 * Malaysia
 * Qatar
 * Singapore
diff --git a/workalendar/asia/__init__.py b/workalendar/asia/__init__.py
index b085843..1792c5c 100644
--- a/workalendar/asia/__init__.py
+++ b/workalendar/asia/__init__.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 from .china import China
 from .hong_kong import HongKong
-from .japan import Japan
+from .japan import Japan, JapanBank
 from .malaysia import Malaysia
 from .qatar import Qatar
 from .singapore import Singapore
@@ -14,6 +14,7 @@ __all__ = (
     'China',
     'HongKong',
     'Japan',
+    'JapanBank',
     'Malaysia',
     'Qatar',
     'Singapore',
diff --git a/workalendar/asia/japan.py b/workalendar/asia/japan.py
index d3c6478..8ecb0b0 100644
--- a/workalendar/asia/japan.py
+++ b/workalendar/asia/japan.py
@@ -20,18 +20,40 @@ class Japan(WesternCalendar, EphemMixin):
         (5, 5, "Children's Day"),
         (11, 3, "Culture Day"),
         (11, 23, "Labour Thanksgiving Day"),
-        (12, 23, "The Emperor's Birthday"),
     )
 
     def get_fixed_holidays(self, year):
         """
         Fixed holidays for Japan.
-
-        As of 2016, the "Mountain Day is being added"
         """
         days = super(Japan, self).get_fixed_holidays(year)
         if year >= 2016:
             days.append((date(year, 8, 11), "Mountain Day"))
+        # Change in Emperor
+        if year < 2019:
+            days.append((date(year, 12, 23), "The Emperor's Birthday"))
+        if year > 2019:
+            days.append((date(year, 2, 23), "The Emperor's Birthday"))
+        # Lots of adjustments for new emperor
+        if year == 2019:
+            days.extend([
+                (date(year, 4, 30), "Coronation Day"),
+                (date(year, 5, 1), "Coronation Day"),
+                (date(year, 5, 2), "Coronation Day"),
+                (date(year, 5, 6), "Children's Day Observed"),
+                (date(year, 8, 12), "Mountain Day Observed"),
+                (date(year, 10, 22), "Enthronement Ceremony Day"),
+                (date(year, 11, 4), "Culture Day Observed"),
+            ])
+        if year == 2020:
+            days.extend([
+                (date(year, 2, 24), "The Emperor's Birthday Observed"),
+                (date(year, 5, 6), "Constitution Memorial Day Observed"),
+                (date(year, 8, 10), "Mountain Day"),
+            ])
+            # Mountain Day is 8/10 this year for some reason
+            # The next year that will be different is 2024
+            days.remove((date(year, 8, 11), "Mountain Day"))
         return days
 
     def get_variable_days(self, year):
@@ -50,4 +72,28 @@ class Japan(WesternCalendar, EphemMixin):
             (equinoxes[1], "Autumnal Equinox Day"),
             (health_and_sport, "Health and Sports Day"),
         ])
+
+        # Marine Day is on a Thursday in 2020 for some year
+        # https://www.timeanddate.com/holidays/japan/sea-day
+        # Health and Sports Day will continue on the 2nd monday
+        # of October, except in 2020 when it will happen in July
+        # https://www.timeanddate.com/holidays/japan/sports-day
+        if year == 2020:
+            days.remove((marine_day, "Marine Day"))
+            days.append((date(2020, 7, 23), "Marine Day"))
+            days.remove((health_and_sport, "Health and Sports Day"))
+            days.append((date(2020, 7, 24), "Health and Sports Day"))
         return days
+
+
+class JapanBank(Japan):
+    """The Bank of Japan is closed additional days other than
+    national holidays.
+    https://www.boj.or.jp/en/about/outline/holi.htm/
+    """
+
+    FIXED_HOLIDAYS = Japan.FIXED_HOLIDAYS + (
+        (1, 2, "New Year Bank Holiday"),
+        (1, 3, "New Year Bank Holiday"),
+        (12, 31, "New Year Bank Holiday"),
+    )


Test patch:
diff --git a/workalendar/tests/test_asia.py b/workalendar/tests/test_asia.py
index 4b94da8..e77c171 100644
--- a/workalendar/tests/test_asia.py
+++ b/workalendar/tests/test_asia.py
@@ -2,7 +2,7 @@ from datetime import date
 from workalendar.tests import GenericCalendarTest
 
 from workalendar.asia import (
-    HongKong, Japan, Qatar, Singapore,
+    HongKong, Japan, JapanBank, Qatar, Singapore,
     SouthKorea, Taiwan, Malaysia, China, Israel
 )
 
@@ -180,6 +180,45 @@ class JapanTest(GenericCalendarTest):
         holidays = self.cal.holidays_set(2017)
         self.assertIn(date(2017, 8, 11), holidays)   # Mountain Day
 
+    def test_year_2019(self):
+        holidays = self.cal.holidays_set(2019)
+        self.assertIn(date(2019, 1, 14), holidays)  # Coming of Age Day
+        self.assertIn(date(2019, 5, 1), holidays)  # Coronation Day
+        self.assertIn(date(2019, 5, 6), holidays)  # Children's Day
+        self.assertIn(date(2019, 8, 12), holidays)  # Mountain Day Observed
+        self.assertIn(date(2019, 11, 4), holidays)  # Culture Day Observed
+
+    def test_year_2020(self):
+        holidays = self.cal.holidays_set(2020)
+        self.assertIn(date(2020, 7, 23), holidays)  # Marine Day
+        self.assertIn(date(2020, 7, 24), holidays)  # Sports Day
+        self.assertIn(date(2020, 8, 10), holidays)  # Mountain Day adjustment
+        self.assertNotIn(date(2020, 8, 11), holidays)  # Mountain Day
+        self.assertNotIn(date(2020, 12, 31), holidays)  # New Year's Bank Day
+
+
+class JapanBankTest(GenericCalendarTest):
+    cal_class = JapanBank
+
+    def test_year_2019(self):
+        holidays = self.cal.holidays_set(2019)
+        self.assertIn(date(2019, 1, 2), holidays)  # New Year's Bank Day
+        self.assertIn(date(2019, 1, 3), holidays)  # New Year's Bank Day
+        self.assertIn(date(2019, 1, 14), holidays)  # Coming of Age Day
+        self.assertIn(date(2019, 5, 3), holidays)  # Constitution Memorial Day
+        self.assertIn(date(2019, 11, 4), holidays)  # Culture Day Observed
+        self.assertIn(date(2019, 12, 31), holidays)  # New Year's Bank Day
+
+    def test_year_2020(self):
+        holidays = self.cal.holidays_set(2020)
+        self.assertIn(date(2020, 1, 2), holidays)  # New Year's Bank Day
+        self.assertIn(date(2020, 1, 3), holidays)  # New Year's Bank Day
+        self.assertIn(date(2020, 12, 31), holidays)  # New Year's Bank Day
+        self.assertIn(date(2020, 8, 10), holidays)  # Mountain Day adjustment
+        self.assertNotIn(date(2020, 8, 11), holidays)  # Mountain Day
+        self.assertIn(date(2020, 7, 23), holidays)  # Marine Day
+        self.assertIn(date(2020, 7, 24), holidays)  # Sports Day
+
 
 class MalaysiaTest(GenericCalendarTest):
     cal_class = Malaysia