Repository: peopledoc/workalendar
Pull request #215 (2019-04-12 14:28:11)

California specific holidays
Some Californian institutions or areas have different holidays:

* California education holidays
* California legal holidays
* Berkeley, California
* San Francisco, California
* West Hollywood, California

~~Source: https://en.wikipedia.org/wiki/Public_holidays_in_the_United_States#California~~

Updated source: https://en.wikipedia.org/wiki/Holidays_with_paid_time_off_in_the_United_States#California

Requires the issue #171 to be solved


Patch:
diff --git a/Changelog.md b/Changelog.md
index 7a4ad3e..1285869 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,7 +2,7 @@
 
 ## master
 
-Nothing here yet.
+- Added California specific calendars: California Education, Berkeley, San Francisco, West Hollywood (#215).
 
 ## v4.3.1 (2019-05-03)
 
diff --git a/workalendar/usa/__init__.py b/workalendar/usa/__init__.py
index 55627f2..95a57b9 100644
--- a/workalendar/usa/__init__.py
+++ b/workalendar/usa/__init__.py
@@ -8,7 +8,10 @@ from .alabama import (
 from .alaska import Alaska
 from .arizona import Arizona
 from .arkansas import Arkansas
-from .california import California
+from .california import (
+    California, CaliforniaEducation, CaliforniaBerkeley,
+    CaliforniaSanFrancisco, CaliforniaWestHollywood,
+)
 from .colorado import Colorado
 from .connecticut import Connecticut
 from .delaware import Delaware
@@ -68,6 +71,8 @@ __all__ = [
     'Arizona',
     'Arkansas',
     'California',
+    'CaliforniaEducation', 'CaliforniaBerkeley', 'CaliforniaSanFrancisco',
+    'CaliforniaWestHollywood',
     'Colorado',
     'Connecticut',
     'Delaware',
diff --git a/workalendar/usa/california.py b/workalendar/usa/california.py
index 6d1eb8b..d31ae50 100644
--- a/workalendar/usa/california.py
+++ b/workalendar/usa/california.py
@@ -3,6 +3,7 @@ from __future__ import (absolute_import, division, print_function,
                         unicode_literals)
 
 from .core import UnitedStates
+from ..core import MON
 from ..registry import iso_register
 
 
@@ -12,3 +13,58 @@ class California(UnitedStates):
     include_thanksgiving_friday = True
     include_cesar_chavez_day = True
     include_columbus_day = False
+
+
+class CaliforniaEducation(California):
+    """California Education
+
+    This administration holds its own calendar. In order to respect the goal
+    of workalendar (to compute (non)working days), we've decided to only retain
+    days when the schools are closed.
+    """
+
+    def get_variable_days(self, year):
+        # usual variable days
+        days = super(CaliforniaEducation, self).get_variable_days(year)
+
+        if year != 2009:
+            days.append(self.get_lincoln_birthday(year))
+
+        days.append((
+            self.get_nth_weekday_in_month(year, 9, MON, 4),
+            'Native American Day'
+        ))
+
+        return days
+
+
+class CaliforniaBerkeley(California):
+    """
+    Berkeley, California
+    """
+    FIXED_HOLIDAYS = California.FIXED_HOLIDAYS + (
+        (5, 19, 'Malcolm X Day'),
+    )
+    include_cesar_chavez_day = False
+    include_lincoln_birthday = True
+    include_columbus_day = True
+    columbus_day_label = "Indigenous People's Day"
+
+
+class CaliforniaSanFrancisco(California):
+    """
+    San Francisco, California
+    """
+    include_cesar_chavez_day = False
+    include_columbus_day = True
+
+
+class CaliforniaWestHollywood(California):
+    """
+    West Hollywood, California
+    """
+    FIXED_HOLIDAYS = California.FIXED_HOLIDAYS + (
+        (5, 22, 'Harvey Milk Day'),
+    )
+    include_cesar_chavez_day = False
+    include_thanksgiving_friday = False


Test patch:
diff --git a/workalendar/tests/test_usa.py b/workalendar/tests/test_usa.py
index d7fbc1a..dd1f450 100644
--- a/workalendar/tests/test_usa.py
+++ b/workalendar/tests/test_usa.py
@@ -5,7 +5,8 @@ from workalendar.tests import GenericCalendarTest
 from workalendar.usa import (
     UnitedStates,
     Alabama, AlabamaBaldwinCounty, AlabamaMobileCounty, AlabamaPerryCounty,
-    Florida, Arkansas, Alaska, Arizona, California,
+    Florida, Arkansas, Alaska, Arizona, California, CaliforniaEducation,
+    CaliforniaBerkeley, CaliforniaSanFrancisco, CaliforniaWestHollywood,
     Colorado, Connecticut, Delaware, DistrictOfColumbia, Georgia, Hawaii,
     Indiana, Illinois, Idaho, Iowa, Kansas, Kentucky, Louisiana, Maine,
     Maryland, Massachusetts, Minnesota, Michigan, Mississippi, Missouri,
@@ -439,6 +440,110 @@ class CaliforniaTest(NoColumbus, UnitedStatesTest):
         self.assertIn(date(2015, 11, 27), holidays)  # Thanksgiving Friday
 
 
+class CaliforniaEducationTest(CaliforniaTest):
+    cal_class = CaliforniaEducation
+
+    def test_specific_lincoln_birthday(self):
+        holidays = self.cal.holidays_set(2018)
+        self.assertIn(date(2018, 2, 12), holidays)  # Lincoln's Birthday
+
+        holidays = self.cal.holidays_set(2019)
+        self.assertIn(date(2019, 2, 12), holidays)  # Lincoln's Birthday
+
+        # Lincoln's Birthday wasn't included in 2009
+        holidays = self.cal.holidays_set(2009)
+        self.assertNotIn(date(2009, 2, 12), holidays)
+
+    def test_specific_native_american_day(self):
+        # Native American Day occurs on the 4th MON of September
+        holidays = self.cal.holidays_set(2018)
+        self.assertIn(date(2018, 9, 24), holidays)  # Native American Day
+
+        holidays = self.cal.holidays_set(2019)
+        self.assertIn(date(2019, 9, 23), holidays)  # Native American Day
+
+
+# Like California, except that it has:
+# * No Chavez Day,
+# * Includes Columbus day, but relabels it.
+# * Adds Lincoln's Birthday.
+class CaliforniaBerkeleyTest(UnitedStatesTest):
+    cal_class = CaliforniaBerkeley
+
+    def test_state_year_2014(self):
+        # Overwriting CaliforniaTest, there's no Chavez Day for Berkeley
+        holidays = self.cal.holidays_set(2014)
+        self.assertNotIn(date(2014, 3, 31), holidays)  # NO Cesar Chavez Day
+        self.assertIn(date(2014, 11, 28), holidays)  # Thanksgiving Friday
+
+    def test_state_year_2015(self):
+        # Overwriting CaliforniaTest, there's no Chavez Day for Berkeley
+        holidays = self.cal.holidays_set(2015)
+        self.assertNotIn(date(2015, 3, 31), holidays)  # NO Cesar Chavez Day
+        self.assertIn(date(2015, 11, 27), holidays)  # Thanksgiving Friday
+
+    def test_specific_lincoln_birthday(self):
+        holidays = self.cal.holidays_set(2018)
+        self.assertIn(date(2018, 2, 12), holidays)  # Lincoln's Birthday
+
+        holidays = self.cal.holidays_set(2019)
+        self.assertIn(date(2019, 2, 12), holidays)  # Lincoln's Birthday
+
+    def test_specific_malcomx_birthday(self):
+        holidays = self.cal.holidays_set(2018)
+        self.assertIn(date(2018, 5, 19), holidays)  # Malcom X Day
+
+        holidays = self.cal.holidays_set(2019)
+        self.assertIn(date(2019, 5, 19), holidays)  # Malcom X Day
+
+    def test_columbus_day_label(self):
+        # Overwrite UnitedStatesTest.test_columbus_day_label
+        _, label = self.cal.get_columbus_day(2019)
+        self.assertEqual(label, "Indigenous People's Day")
+
+
+# Like California, except:
+# * No Chavez Day,
+# * Added Columbus Day
+class CaliforniaSanFranciscoTest(UnitedStatesTest):
+    cal_class = CaliforniaSanFrancisco
+
+    def test_state_year_2014(self):
+        holidays = self.cal.holidays_set(2014)
+        self.assertNotIn(date(2014, 3, 31), holidays)  # NO Cesar Chavez Day
+        self.assertIn(date(2014, 11, 28), holidays)  # Thanksgiving Friday
+
+    def test_state_year_2015(self):
+        holidays = self.cal.holidays_set(2015)
+        self.assertNotIn(date(2015, 3, 31), holidays)  # NO Cesar Chavez Day
+        self.assertIn(date(2015, 11, 27), holidays)  # Thanksgiving Friday
+
+
+# Like California, except:
+# * No Chavez Day,
+# * No Thanksgiving Friday
+# * Added Harvey Milk Day
+class CaliforniaWestHollywoodTest(NoColumbus, UnitedStatesTest):
+    cal_class = CaliforniaWestHollywood
+
+    def test_state_year_2014(self):
+        holidays = self.cal.holidays_set(2014)
+        self.assertNotIn(date(2014, 3, 31), holidays)  # NO Cesar Chavez Day
+        self.assertNotIn(date(2014, 11, 28), holidays)  # Thanksgiving Friday
+
+    def test_state_year_2015(self):
+        holidays = self.cal.holidays_set(2015)
+        self.assertNotIn(date(2015, 3, 31), holidays)  # NO Cesar Chavez Day
+        self.assertNotIn(date(2015, 11, 27), holidays)  # Thanksgiving Friday
+
+    def test_harvey_milk_day(self):
+        holidays = self.cal.holidays_set(2018)
+        self.assertIn(date(2018, 5, 22), holidays)  # Harvey Milk Day
+
+        holidays = self.cal.holidays_set(2019)
+        self.assertIn(date(2019, 5, 22), holidays)  # Harvey Milk Day
+
+
 class ColoradoTest(UnitedStatesTest):
     cal_class = Colorado
     # Colorado has only federal state holidays.