From ef9fc27a420a8e65937900870c846248a3421358 Mon Sep 17 00:00:00 2001 From: Koki Nomura Date: Mon, 17 Apr 2017 12:37:29 +0900 Subject: [PATCH] Add Japanese holidays --- holidays.py | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests.py | 119 ++++++++++++++++++++++++++++++++++++ 2 files changed, 290 insertions(+) diff --git a/holidays.py b/holidays.py index ecb463a07a..8894919131 100644 --- a/holidays.py +++ b/holidays.py @@ -2224,3 +2224,174 @@ def _populate(self, year): class NO(Norway): pass + + +class Japan(HolidayBase): + # https://en.wikipedia.org/wiki/Public_holidays_in_Japan + + def __init__(self, **kwargs): + self.country = 'JP' + HolidayBase.__init__(self, **kwargs) + + def _populate(self, year): + if year < 1949 or year > 2050: + raise NotImplementedError + + # New Year's Day + self[date(year, 1, 1)] = "元日" + + # Coming of Age Day + if year <= 1999: + self[date(year, 1, 15)] = "成人の日" + else: + self[date(year, 1, 1) + rd(weekday=MO(+2))] = "成人の日" + + # Foundation Day + self[date(year, 2, 11)] = "建国記念の日" + + # Vernal Equinox Day + self[self._vernal_equinox_day(year)] = "春分の日" + + # The former Emperor's Birthday, Greenery Day or Showa Day + if year <= 1988: + self[date(year, 4, 29)] = "天皇誕生日" + elif year <= 2006: + self[date(year, 4, 29)] = "みどりの日" + else: + self[date(year, 4, 29)] = "昭和の日" + + # Constitution Memorial Day + self[date(year, 5, 3)] = "憲法記念日" + + # Greenery Day + if year >= 2007: + self[date(year, 5, 4)] = "みどりの日" + + # Children's Day + self[date(year, 5, 5)] = "こどもの日" + + # Marine Day + if year >= 1996 and year <= 2002: + self[date(year, 7, 20)] = "海の日" + elif year >= 2003: + self[date(year, 7, 1) + rd(weekday=MO(+3))] = "海の日" + + # Mountain Day + if year >= 2016: + self[date(year, 8, 11)] = "山の日" + + # Respect for the Aged Day + if year >= 1966 and year <= 2002: + self[date(year, 9, 15)] = "敬老の日" + elif year >= 2003: + self[date(year, 9, 1) + rd(weekday=MO(+3))] = "敬老の日" + + # Autumnal Equinox Day + self[self._autumnal_equinox_day(year)] = "秋分の日" + + # Health and Sports Day + if year >= 1966 and year <= 1999: + self[date(year, 10, 10)] = "体育の日" + elif year >= 2000: + self[date(year, 10, 1) + rd(weekday=MO(+2))] = "体育の日" + + # Culture Day + self[date(year, 11, 3)] = "文化の日" + + # Labour Thanksgiving Day + self[date(year, 11, 23)] = "勤労感謝の日" + + # The Emperor's Birthday + if year >= 1989: + self[date(year, 12, 23)] = "天皇誕生日" + + # A weekday between national holidays becomes a holiday too (国民の休日) + self._add_national_holidays(year) + + # Substitute holidays + self._add_substitute_holidays(year) + + def _vernal_equinox_day(self, year): + day = 20 + if year % 4 == 0: + if year <= 1956: + day = 21 + elif year >= 2092: + day = 19 + elif year % 4 == 1: + if year <= 1989: + day = 21 + elif year % 4 == 2: + if year <= 2022: + day = 21 + elif year % 4 == 3: + if year <= 2055: + day = 21 + return date(year, 3, day) + + def _autumnal_equinox_day(self, year): + day = 22 + if year % 4 == 0: + if year <= 2008: + day = 23 + elif year % 4 == 1: + if year <= 2041: + day = 23 + elif year % 4 == 2: + if year <= 2074: + day = 23 + elif year % 4 == 3: + if year <= 1979: + day = 24 + else: + day = 23 + return date(year, 9, day) + + def _add_national_holidays(self, year): + if year in (1993, 1999, 2004, 1988, 1994, 2005, 1989, 1995, 2000, 2006, + 1990, 2001, 1991, 1996, 2002): + self[date(year, 5, 4)] = "国民の休日" + + if year in (2032, 2049, 2060, 2077, 2088, 2094): + self[date(year, 9, 21)] = "国民の休日" + + if year in (2009, 2015, 2026, 2037, 2043, 2054, 2065, 2071, 2099): + self[date(year, 9, 22)] = "国民の休日" + + def _add_substitute_holidays(self, year): + table = ( + (1, 2, (1978, 1984, 1989, 1995, 2006, 2012, 2017, 2023, 2034, 2040, + 2045)), + (1, 16, (1978, 1984, 1989, 1995)), + (2, 12, (1979, 1990, 1996, 2001, 2007, 2018, 2024, 2029, 2035, + 2046)), + (3, 21, (1988, 2005, 2016, 2033, 2044, 2050)), + (3, 22, (1982, 1999, 2010, 2027)), + (4, 30, (1973, 1979, 1984, 1990, 2001, 2007, 2012, 2018, 2029, + 2035, 2040, 2046)), + (5, 4, (1981, 1987, 1992, 1998)), + (5, 6, (1985, 1991, 1996, 2002, 2013, 2019, 2024, 2030, 2041, 2047, + 2008, 2014, 2025, 2031, 2036, 2042, 2009, 2015, 2020, 2026, + 2037, 2043, 2048)), + (7, 21, (1997,)), + (8, 12, (2019, 2024, 2030, 2041, 2047)), + (9, 16, (1974, 1985, 1991, 1996, 2002)), + (9, 23, (2024,)), + (9, 24, (1973, 1984, 1990, 2001, 2007, 2018, 2029, 2035, 2046)), + (10, 11, (1976, 1982, 1993, 1999)), + (11, 4, (1974, 1985, 1991, 1996, 2002, 2013, 2019, 2024, 2030, + 2041, 2047)), + (11, 24, (1975, 1980, 1986, 1997, 2003, 2008, 2014, 2025, 2031, + 2036, 2042)), + (12, 24, (1990, 2001, 2007, 2012, 2018)), + ) + for holiday in table: + month = holiday[0] + day = holiday[1] + years = holiday[2] + if year in years: + self[date(year, month, day)] = "振替休日" + + +class JP(Japan): + pass diff --git a/tests.py b/tests.py index ab7167998e..d93d5b6a5f 100644 --- a/tests.py +++ b/tests.py @@ -3000,5 +3000,124 @@ def test_not_holiday(self): self.assertFalse('2016-12-28' in self.holidays_with_sundays) +class TestJapan(unittest.TestCase): + def setUp(self): + self.holidays = holidays.Japan(observed=False) + + def test_new_years_day(self): + self.assertTrue(date(1949, 1, 1) in self.holidays) + self.assertTrue(date(2017, 1, 1) in self.holidays) + self.assertTrue(date(2050, 1, 1) in self.holidays) + + def test_coming_of_age(self): + self.assertTrue(date(1999, 1, 15)in self.holidays) + self.assertTrue(date(2000, 1, 10)in self.holidays) + self.assertTrue(date(2017, 1, 9)in self.holidays) + self.assertTrue(date(2030, 1, 14)in self.holidays) + self.assertTrue(date(2050, 1, 10)in self.holidays) + + self.assertFalse(date(2000, 1, 15)in self.holidays) + self.assertFalse(date(2017, 1, 15)in self.holidays) + self.assertFalse(date(2030, 1, 15)in self.holidays) + + def test_foundation_day(self): + self.assertTrue(date(1949, 2, 11) in self.holidays) + self.assertTrue(date(2017, 2, 11) in self.holidays) + self.assertTrue(date(2050, 2, 11) in self.holidays) + + def test_vernal_equinox_day(self): + self.assertTrue(date(1960, 3, 20) in self.holidays) + self.assertTrue(date(1970, 3, 21) in self.holidays) + self.assertTrue(date(1980, 3, 20) in self.holidays) + self.assertTrue(date(1990, 3, 21) in self.holidays) + self.assertTrue(date(2000, 3, 20) in self.holidays) + self.assertTrue(date(2010, 3, 21) in self.holidays) + self.assertTrue(date(2017, 3, 20) in self.holidays) + self.assertTrue(date(2020, 3, 20) in self.holidays) + self.assertTrue(date(2030, 3, 20) in self.holidays) + self.assertTrue(date(2040, 3, 20) in self.holidays) + + def test_showa_day(self): + self.assertTrue(date(1950, 4, 29) in self.holidays) + self.assertTrue(date(1990, 4, 29) in self.holidays) + self.assertTrue(date(2010, 4, 29) in self.holidays) + + def test_constitution_memorial_day(self): + self.assertTrue(date(1950, 5, 3) in self.holidays) + self.assertTrue(date(2000, 5, 3) in self.holidays) + self.assertTrue(date(2050, 5, 3) in self.holidays) + + def test_greenery_day(self): + self.assertFalse(date(1950, 5, 4) in self.holidays) + self.assertTrue(date(2007, 5, 4) in self.holidays) + self.assertTrue(date(2050, 5, 4) in self.holidays) + + def test_childrens_day(self): + self.assertTrue(date(1950, 5, 5) in self.holidays) + self.assertTrue(date(2000, 5, 5) in self.holidays) + self.assertTrue(date(2050, 5, 5) in self.holidays) + + def test_marine_day(self): + self.assertFalse(date(1950, 7, 20) in self.holidays) + self.assertTrue(date(2000, 7, 20) in self.holidays) + self.assertTrue(date(2003, 7, 21) in self.holidays) + self.assertTrue(date(2017, 7, 17) in self.holidays) + self.assertTrue(date(2050, 7, 18) in self.holidays) + + def test_mountain_day(self): + self.assertFalse(date(1950, 8, 11) in self.holidays) + self.assertFalse(date(2015, 8, 11) in self.holidays) + self.assertTrue(date(2016, 8, 11) in self.holidays) + self.assertTrue(date(2017, 8, 11) in self.holidays) + self.assertTrue(date(2050, 8, 11) in self.holidays) + + def test_respect_for_the_aged_day(self): + self.assertFalse(date(1965, 9, 15) in self.holidays) + self.assertTrue(date(1966, 9, 15) in self.holidays) + self.assertTrue(date(2002, 9, 15) in self.holidays) + self.assertTrue(date(2003, 9, 15) in self.holidays) + self.assertFalse(date(2004, 9, 15) in self.holidays) + self.assertTrue(date(2004, 9, 20) in self.holidays) + self.assertTrue(date(2017, 9, 18) in self.holidays) + self.assertTrue(date(2050, 9, 19) in self.holidays) + + def test_autumnal_equinox_day(self): + self.assertTrue(date(2000, 9, 23) in self.holidays) + self.assertTrue(date(2010, 9, 23) in self.holidays) + self.assertTrue(date(2017, 9, 23) in self.holidays) + self.assertTrue(date(2020, 9, 22) in self.holidays) + self.assertTrue(date(2030, 9, 23) in self.holidays) + + def test_health_and_sports_day(self): + self.assertFalse(date(1965, 10, 10) in self.holidays) + self.assertTrue(date(1966, 10, 10) in self.holidays) + self.assertTrue(date(1999, 10, 10) in self.holidays) + self.assertFalse(date(2000, 10, 10) in self.holidays) + self.assertTrue(date(2000, 10, 9) in self.holidays) + self.assertTrue(date(2017, 10, 9) in self.holidays) + self.assertTrue(date(2050, 10, 10) in self.holidays) + + def test_culture_day(self): + self.assertTrue(date(1950, 11, 3) in self.holidays) + self.assertTrue(date(2000, 11, 3) in self.holidays) + self.assertTrue(date(2050, 11, 3) in self.holidays) + + def test_labour_thanks_giving_day(self): + self.assertTrue(date(1950, 11, 23) in self.holidays) + self.assertTrue(date(2000, 11, 23) in self.holidays) + self.assertTrue(date(2050, 11, 23) in self.holidays) + + def test_emperors_birthday(self): + self.assertTrue(date(1989, 12, 23) in self.holidays) + self.assertTrue(date(2017, 12, 23) in self.holidays) + self.assertTrue(date(2050, 12, 23) in self.holidays) + + def test_invalid_years(self): + self.assertRaises(NotImplementedError, + lambda: date(1948, 1, 1) in self.holidays) + self.assertRaises(NotImplementedError, + lambda: date(2051, 1, 1) in self.holidays) + + if __name__ == "__main__": unittest.main()