Repository: peopledoc/workalendar
Pull request #431 (2019-11-29 13:58:39)

Ftatarli argentina holidays
This PR completes and thus, closes #419


- [x] Tests with a significant number of years to be tested for your calendar.
- [x] Docstrings for the Calendar class and specific methods.
- [x] 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`` (#)". **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 51ebbb0..ce97b32 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -4,6 +4,7 @@
 
 - Small refactorings on the Gevena (Switzerland) holiday class.
 - Update China's public holidays for 2020.
+- Added Argentina calendar, by @ftatarli (#419).
 
 ## v7.1.1 (2019-11-22)
 
diff --git a/README.rst b/README.rst
index 8b565cf..085b01f 100644
--- a/README.rst
+++ b/README.rst
@@ -120,6 +120,7 @@ Europe
 America
 -------
 
+* Argentina
 * Barbados
 * Brazil (all states, cities and for bank transactions, except the city of Viana)
 * Canada (including provincial and territory holidays)
diff --git a/workalendar/america/__init__.py b/workalendar/america/__init__.py
index 20d92c1..55897d9 100644
--- a/workalendar/america/__init__.py
+++ b/workalendar/america/__init__.py
@@ -29,6 +29,7 @@ from .colombia import Colombia
 from .mexico import Mexico
 from .panama import Panama
 from .paraguay import Paraguay
+from .argentina import Argentina
 
 
 __all__ = (
@@ -115,4 +116,5 @@ __all__ = (
     'Mexico',
     'Panama',
     'Paraguay',
+    'Argentina',
 )
diff --git a/workalendar/america/argentina.py b/workalendar/america/argentina.py
new file mode 100644
index 0000000..75e4d0d
--- /dev/null
+++ b/workalendar/america/argentina.py
@@ -0,0 +1,133 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+from datetime import timedelta, date
+from workalendar.core import WesternCalendar, ChristianMixin
+from ..core import MON, TUE, WED, THU, FRI, SAT
+from ..registry_tools import iso_register
+
+
+@iso_register('AR')
+class Argentina(WesternCalendar, ChristianMixin):
+    'Argentina'
+
+    include_good_friday = True
+    include_easter_saturday = True
+    include_easter_sunday = True
+    include_christmas = True
+
+    FIXED_HOLIDAYS = WesternCalendar.FIXED_HOLIDAYS + (
+        (3, 24, "Día de la Memoria"),
+        (4, 2, "Día de las Malvinas"),
+        (5, 1, "Día del Trabajador"),
+        (5, 25, "Día de la Revolución de Mayo"),
+        (6, 20, "Día Paso a la Inmortalidad del General Manuel Belgrano"),
+        (7, 9, "Día de la Independencia"),
+        (12, 8, "Día de la Inmaculada Concepción de María"),
+    )
+
+    def get_variable_days(self, year):
+
+        days = super(Argentina, self).get_variable_days(year)
+        days.append(
+            (self.get_easter_sunday(year) - timedelta(days=48),
+                "Carnival Lunes"))
+
+        days.append(
+            (self.get_easter_sunday(year) - timedelta(days=47),
+                "Carnival"))
+
+        days.append(
+            (self.get_general_guemes_day(year)))
+
+        days.append(
+            (self.get_general_martin_day(year)))
+
+        days.append(
+            (self.get_soberania_day(year)))
+
+        days.append(
+            (self.get_diversidad_day(year)))
+
+        return days
+
+    def get_general_guemes_day(self, year):
+        """
+        Día Paso a la Inmortalidad del General Martín Miguel de Güemes.
+
+        Happens on June 17th, except:
+
+        * if it happens on a THU, it's shifted to the next MON.
+        * if it happens on a WED, it's shifted to the MON before this date.
+        """
+        general_guemes_day = date(year, 6, 17)
+
+        if general_guemes_day.weekday() == THU:
+            general_guemes_day = Argentina.get_first_weekday_after(
+                date(year, 6, 17), MON)
+        elif general_guemes_day.weekday() == WED:
+            # Monday of the same week
+            general_guemes_day = general_guemes_day - timedelta(days=2)
+        else:
+            general_guemes_day
+
+        return (general_guemes_day,
+                "Día Paso a la Inmortalidad del " +
+                "General Martín Miguel de Güemes")
+
+    def get_general_martin_day(self, year):
+        """
+        Día Paso a la Inmortalidad del Gral. José de San Martín
+
+        Third MON of August.
+        """
+        general_martin_day = Argentina.get_nth_weekday_in_month(
+            year, 8, MON, 3
+        )
+
+        return (general_martin_day,
+                "Día Paso a la Inmortalidad del " +
+                "Gral. José de San Martín")
+
+    def get_soberania_day(self, year):
+        """
+        Día de la Soberanía Nacional
+
+        Happens on the 3rd MON of November after the first Friday.
+        """
+        first_friday_november = Argentina.get_nth_weekday_in_month(
+            year, 11, FRI, 1
+        )
+
+        soberania_day = Argentina.get_nth_weekday_in_month(
+            year, 11, MON, n=3, start=first_friday_november
+        )
+
+        return (soberania_day, "Día de la Soberanía Nacional")
+
+    def get_diversidad_day(self, year):
+        """
+        Día del Respeto a la Diversidad Cultural
+
+        The pivot date is the 12th of October.
+
+        * If it happens on a TUE, it's shifter on the 11th of Oct.
+        * If it happens on a WED, THU, FRI or SAT, it's shifted on the first
+          MON after this date.
+        * Else, it's on the 12th of October.
+        """
+        diversidad_day = date(year, 10, 12)
+
+        if (diversidad_day.weekday() == WED or
+                diversidad_day.weekday() == THU or
+                diversidad_day.weekday() == FRI or
+                diversidad_day.weekday() == SAT):
+            diversidad_day = Argentina.get_first_weekday_after(
+                date(year, 10, 12), MON
+            )
+        elif diversidad_day.weekday() == TUE:
+            diversidad_day = diversidad_day - timedelta(days=1)
+        else:
+            diversidad_day
+
+        return (diversidad_day,
+                "Día del Respeto a la Diversidad Cultural")


Test patch:
diff --git a/workalendar/tests/test_america.py b/workalendar/tests/test_america.py
index 0af70fb..95015c9 100644
--- a/workalendar/tests/test_america.py
+++ b/workalendar/tests/test_america.py
@@ -2,7 +2,100 @@
 from datetime import date
 from workalendar.tests import GenericCalendarTest
 from workalendar.america import Colombia, Barbados
-from workalendar.america import Mexico, Chile, Panama, Paraguay
+from workalendar.america import Mexico, Chile, Panama, Paraguay, Argentina
+
+
+class ArgentinaTest(GenericCalendarTest):
+    cal_class = Argentina
+
+    def test_holidays_2018(self):
+        holidays = self.cal.holidays_set(2018)
+        # 1. Año Nuevo
+        self.assertIn(date(2018, 1, 1), holidays)
+        # 2. Carnaval
+        self.assertIn(date(2018, 2, 12), holidays)
+        # 3. Carnaval
+        self.assertIn(date(2018, 2, 13), holidays)
+        # 4. Día de la Memoria
+        self.assertIn(date(2018, 3, 24), holidays)
+        # 5. Día del Veterano y de los Caídos en la Guerra de Malvinas
+        self.assertIn(date(2018, 4, 2), holidays)
+        # 6. Viernes Santo
+        self.assertIn(date(2018, 3, 30), holidays)
+        # 7. Día del Trabajador
+        self.assertIn(date(2018, 5, 1), holidays)
+        # 8. Día de la Revolución de Mayo
+        self.assertIn(date(2018, 5, 25), holidays)
+        # 9. Día Paso a la Inmortalidad del General Manuel Belgrano
+        self.assertIn(date(2018, 6, 20), holidays)
+        # 10. Día de la Independencia
+        self.assertIn(date(2018, 7, 9), holidays)
+        # 11. Inmaculada Concepción de María
+        self.assertIn(date(2018, 12, 8), holidays)
+        # 12. Navidad
+        self.assertIn(date(2018, 12, 25), holidays)
+        # variable days
+        # 13. Día Paso a la Inmortalidad del General Martín Miguel de Güemes
+        self.assertIn(date(2018, 6, 17), holidays)
+        # 14. Paso a la Inmortalidad del General José de San Martín
+        self.assertIn(date(2018, 8, 20), holidays)
+        # 15. Día del Respeto a la Diversidad Cultural
+        self.assertIn(date(2018, 10, 15), holidays)
+        # 16. Día de la Soberanía Nacional
+        self.assertIn(date(2018, 11, 19), holidays)
+
+    def test_holidays_2019(self):
+        holidays = self.cal.holidays_set(2019)
+        self.assertIn(date(2019, 1, 1), holidays)
+        self.assertIn(date(2019, 3, 4), holidays)
+        self.assertIn(date(2019, 3, 5), holidays)
+        self.assertIn(date(2019, 3, 24), holidays)
+        self.assertIn(date(2019, 4, 2), holidays)
+        self.assertIn(date(2019, 4, 19), holidays)
+        self.assertIn(date(2019, 5, 1), holidays)
+        self.assertIn(date(2019, 5, 25), holidays)
+        self.assertIn(date(2019, 6, 20), holidays)
+        self.assertIn(date(2019, 7, 9), holidays)
+        self.assertIn(date(2019, 12, 8), holidays)
+        self.assertIn(date(2019, 12, 25), holidays)
+        # variable days
+        self.assertIn(date(2019, 6, 17), holidays)
+        self.assertIn(date(2019, 8, 19), holidays)
+        self.assertIn(date(2019, 10, 14), holidays)
+        self.assertIn(date(2019, 11, 18), holidays)
+
+    def test_holidays_2020(self):
+        holidays = self.cal.holidays_set(2020)
+        self.assertIn(date(2020, 1, 1), holidays)
+        self.assertIn(date(2020, 2, 24), holidays)
+        self.assertIn(date(2020, 2, 25), holidays)
+        self.assertIn(date(2020, 3, 24), holidays)
+        self.assertIn(date(2020, 4, 2), holidays)
+        self.assertIn(date(2020, 4, 10), holidays)
+        self.assertIn(date(2020, 5, 1), holidays)
+        self.assertIn(date(2020, 5, 25), holidays)
+        self.assertIn(date(2020, 6, 20), holidays)
+        self.assertIn(date(2020, 7, 9), holidays)
+        self.assertIn(date(2020, 12, 8), holidays)
+        self.assertIn(date(2020, 12, 25), holidays)
+        # variable days
+        self.assertIn(date(2020, 6, 15), holidays)
+        self.assertIn(date(2020, 8, 17), holidays)
+        self.assertIn(date(2020, 10, 12), holidays)
+        self.assertIn(date(2020, 11, 23), holidays)
+
+    def test_holidays_2021(self):
+        # Testing it because June 17th happens on THU (general_guemes_day).
+        holidays = self.cal.holidays_set(2021)
+        # Not happening on June 17
+        self.assertNotIn(date(2021, 6, 17), holidays)
+        # Happens on the 1st MON after this date.
+        self.assertIn(date(2021, 6, 20), holidays)
+
+        # Also, Día del Respeto a la Diversidad Cultural is shifted
+        self.assertNotIn(date(2021, 10, 12), holidays)
+        # The day before
+        self.assertIn(date(2021, 10, 11), holidays)
 
 
 class ChileTest(GenericCalendarTest):
diff --git a/workalendar/tests/test_registry_america.py b/workalendar/tests/test_registry_america.py
index 393090a..aa45ac8 100644
--- a/workalendar/tests/test_registry_america.py
+++ b/workalendar/tests/test_registry_america.py
@@ -27,7 +27,9 @@ from workalendar.america import (
     Nunavut,
 
 )
-from workalendar.america import Chile, Colombia, Mexico, Panama, Paraguay
+from workalendar.america import (
+    Argentina, Chile, Colombia, Mexico, Panama, Paraguay
+)
 
 from workalendar.registry import registry
 
@@ -85,6 +87,7 @@ class RegistryAmerica(TestCase):
         self.assertIn(Canada, classes)
         self._check_canada_provinces(classes)
 
+        self.assertIn(Argentina, classes)
         self.assertIn(Chile, classes)
         self.assertIn(Colombia, classes)
         self.assertIn(Mexico, classes)