Repository: vacanza/holidays (python)

Issue:
Missing "Thiruvalluvar Day" and "Uzhavar Thinam" in India (Tamil Nadu) regional holidays
<h1>Holidays Missed in Tamil Nadu, India:</h1>

<b>The day following Pongal, Thiruvalluvar Day.</b>

<b>Two days following Pongal, Uzhavar Thinam.</b>

<h1>Problem:</h1>

At the moment, Pongal and Makar Sankranti are considered to be the same holiday.

In 2003, Makar Sankranti was celebrated on January 14, while Pongal was celebrated on January 15 in Tamil Nadu.

Treating them as the same causes incorrect holiday representation.

<h2>Reference:</h2>

https://www.tn.gov.in/sites/default/holidays/public_e_792_2024.pdf
https://www.prokerala.com/general/calendar/tamilcalendar.php?year=2003&mon=january&la=ta&sb=1
https://www.timeanddate.com/holidays/india/makar-sankranti

Pull request:
Update India holidays: add missing Tamil Nadu holidays
<!--
  Thanks for contributing to holidays!
-->

## Proposed change

<h3>Added missing holidays for the Tamil Nadu subdivision (India).</h3>

Notably, Pongal and Marker Sankranti dates differ slightly. To handle this correctly, I introduced a separate add_pongal() function for Pongal-related holidays.

For accurate historical data, I referred to:
<a href="https://www.tamildailycalendar.com/tamil_monthly_calendar.php?month=01&year=2005&&msg=Tamil%20Monthly%20Calendar%202015">Tamil Daily Calendar (2005–2025)</a>

<a href="https://www.prokerala.com/general/calendar/tamilcalendar.php?mon=january&sb=1&year=2003">Prokerala Tamil Calendar (2001–2005)</a>

<h4>The sequence of holidays around Pongal is:</h4>

1) Bhogi (not declared as a public holiday)

2) Pongal (Main festival)

3) Thiruvalluvar Day (the day after Pongal)

4) Uzhavar Thirunal (the day after Thiruvalluvar Day)

This structure aligns with the traditional four-day Pongal celebrations in Tamil Nadu.

<!--
  Describe the big picture of your changes.
  Don't forget to link your PR to an existing issue if any.
-->

Your PR description goes here.

## Type of change

1) Added missing public and optional holidays.

2) Created a new add_pongal() function for better handling of Pongal-related holidays.

Closes #2500 

<!--
  Type of change you want to introduce. Please, check one (1) box only!
  If your PR requires multiple boxes to be checked, most likely it needs to
  be split into multiple PRs.
-->

- [ ] New country/market holidays support (thank you!)
- [x] Supported country/market holidays update (calendar discrepancy fix, localization)
- [ ] Existing code/documentation/test/process quality improvement (best practice, cleanup, refactoring, optimization)
- [ ] Dependency update (version deprecation/pin/upgrade)
- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] Breaking change (a code change causing existing functionality to break)
- [ ] New feature (new `holidays` functionality in general)

## Checklist

<!--
  Put an `x` in the boxes that apply. You can change them after PR is created.
-->

- [x] I've followed the [contributing guidelines][contributing-guidelines]
- [x] I've successfully run `make check`, all checks and tests are green

<!--
  Thanks again for your contribution!
-->

[contributing-guidelines]: https://github.com/vacanza/holidays/blob/dev/CONTRIBUTING.md
[docs]: https://github.com/vacanza/holidays/tree/dev/docs/source


Patch:
diff --git a/holidays/calendars/hindu.py b/holidays/calendars/hindu.py
index 03a7f9ce..86a4e9df 100644
--- a/holidays/calendars/hindu.py
+++ b/holidays/calendars/hindu.py
@@ -35,6 +35,7 @@ MAHA_SHIVARATRI = "MAHA_SHIVARATRI"
 MAHAVIR_JAYANTI = "MAHAVIR_JAYANTI"
 MAKAR_SANKRANTI = "MAKAR_SANKRANTI"
 ONAM = "ONAM"
+PONGAL = "PONGAL"
 RAKSHA_BANDHAN = "RAKSHA_BANDHAN"
 RAM_NAVAMI = "RAM_NAVAMI"
 SHARAD_NAVRATRI = "SHARAD_NAVRATRI"
@@ -865,6 +866,44 @@ class _HinduLunisolar:
         2035: (SEP, 14),
     }
 
+    PONGAL_DATES = {
+        2001: (JAN, 14),
+        2002: (JAN, 14),
+        2003: (JAN, 15),
+        2004: (JAN, 15),
+        2005: (JAN, 14),
+        2006: (JAN, 14),
+        2007: (JAN, 15),
+        2008: (JAN, 15),
+        2009: (JAN, 14),
+        2010: (JAN, 14),
+        2011: (JAN, 15),
+        2012: (JAN, 15),
+        2013: (JAN, 14),
+        2014: (JAN, 14),
+        2015: (JAN, 15),
+        2016: (JAN, 15),
+        2017: (JAN, 14),
+        2018: (JAN, 14),
+        2019: (JAN, 15),
+        2020: (JAN, 15),
+        2021: (JAN, 14),
+        2022: (JAN, 14),
+        2023: (JAN, 15),
+        2024: (JAN, 15),
+        2025: (JAN, 14),
+        2026: (JAN, 14),
+        2027: (JAN, 15),
+        2028: (JAN, 15),
+        2029: (JAN, 14),
+        2030: (JAN, 14),
+        2031: (JAN, 15),
+        2032: (JAN, 15),
+        2033: (JAN, 14),
+        2034: (JAN, 14),
+        2035: (JAN, 15),
+    }
+
     # https://www.timeanddate.com/holidays/india/raksha-bandhan
     RAKSHA_BANDHAN_DATES = {
         2001: (AUG, 4),
@@ -1270,6 +1309,9 @@ class _HinduLunisolar:
     def holi_date(self, year: int) -> tuple[Optional[date], bool]:
         return self._get_holiday(HOLI, year)
 
+    def pongal_date(self, year: int) -> tuple[Optional[date], bool]:
+        return self._get_holiday(PONGAL, year)
+
     def janmashtami_date(self, year: int) -> tuple[Optional[date], bool]:
         return self._get_holiday(JANMASHTAMI, year)
 
diff --git a/holidays/countries/india.py b/holidays/countries/india.py
index 56ee2be0..9df99893 100644
--- a/holidays/countries/india.py
+++ b/holidays/countries/india.py
@@ -37,6 +37,9 @@ class India(
         * <https://www.calendarlabs.com/holidays/india/2021>
         * <https://slusi.dacnet.nic.in/watershedatlas/list_of_state_abbreviation.htm>
         * <https://vahan.parivahan.gov.in/vahan4dashboard/>
+        * Tamil Nadu:
+            * [Tamil Monthly Calendar](https://www.tamildailycalendar.com/tamil_monthly_calendar.php)
+            * [Tamil Calendar](https://www.prokerala.com/general/calendar/tamilcalendar.php)
     """
 
     country = "IN"
@@ -456,7 +459,11 @@ class India(
     # Tamil Nadu.
     def _populate_subdiv_tn_public_holidays(self):
         # Pongal.
-        self._add_makar_sankranti(tr("Pongal"))
+        self._add_pongal(tr("Pongal"))
+        # Thiruvalluvar Day / Mattu Pongal.
+        self._add_thiruvalluvar_day(tr("Thiruvalluvar Day / Mattu Pongal"))
+        # Uzhavar Thirunal.
+        self._add_uzhavar_thirunal(tr("Uzhavar Thirunal"))
         # Dr. B. R. Ambedkar Jayanti.
         self._add_holiday_apr_14(tr("Dr. B. R. Ambedkar's Jayanti"))
         # Puthandu.
diff --git a/holidays/groups/hindu.py b/holidays/groups/hindu.py
index e08c156d..6843cf1a 100644
--- a/holidays/groups/hindu.py
+++ b/holidays/groups/hindu.py
@@ -28,7 +28,7 @@ class HinduCalendarHolidays(EasternCalendarHolidays):
         self._hindu_calendar_show_estimated = show_estimated
 
     def _add_hindu_calendar_holiday(
-        self, name: str, dt_estimated: tuple[Optional[date], bool]
+        self, name: str, dt_estimated: tuple[Optional[date], bool], days_delta: int = 0
     ) -> Optional[date]:
         """
         Add Hindu calendar holiday.
@@ -38,7 +38,7 @@ class HinduCalendarHolidays(EasternCalendarHolidays):
         """
 
         return self._add_eastern_calendar_holiday(
-            name, dt_estimated, self._hindu_calendar_show_estimated
+            name, dt_estimated, self._hindu_calendar_show_estimated, days_delta
         )
 
     def _add_hindu_calendar_holiday_set(
@@ -256,6 +256,18 @@ class HinduCalendarHolidays(EasternCalendarHolidays):
         """
         return self._add_hindu_calendar_holiday(name, self._hindu_calendar.onam_date(self._year))
 
+    def _add_pongal(self, name) -> Optional[date]:
+        """
+        Add Pongal.
+
+        Pongal is a major harvest festival celebrated in Tamil Nadu, India, marking the
+        beginning of the sun's northward journey (Uttarayana). It is usually observed
+        on January 14th or 15th every year, coinciding with the Tamil month of Thai.
+        The festival is dedicated to the Sun God and marks a season of prosperity and abundance.
+        https://en.wikipedia.org/wiki/Pongal_(festival)
+        """
+        return self._add_hindu_calendar_holiday(name, self._hindu_calendar.pongal_date(self._year))
+
     def _add_raksha_bandhan(self, name) -> Optional[date]:
         """
         Add Raksha Bandhan.
@@ -306,6 +318,36 @@ class HinduCalendarHolidays(EasternCalendarHolidays):
             name, self._hindu_calendar.thaipusam_date(self._year)
         )
 
+    def _add_thiruvalluvar_day(self, name) -> Optional[date]:
+        """
+        Add Thiruvalluvar Day and Mattu Pongal.
+
+        Thiruvalluvar Day and Mattu Pongal are celebrated in Tamil Nadu, India, as part
+        of the Pongal festival. Thiruvalluvar Day honors the classical Tamil poet and
+        philosopher Thiruvalluvar, while Mattu Pongal is dedicated to cattle, recognizing
+        their importance in agriculture. Both events usually fall on January 15th or 16th
+        each year during the Tamil month of Thai.
+        https://en.wikipedia.org/wiki/Thiruvalluvar_Day
+        https://en.wikipedia.org/wiki/Pongal_(festival)#Mattu_Pongal
+        """
+        return self._add_hindu_calendar_holiday(
+            name, self._hindu_calendar.pongal_date(self._year), days_delta=+1
+        )
+
+    def _add_uzhavar_thirunal(self, name) -> Optional[date]:
+        """
+        Add Uzhavar Thirunal.
+
+        Uzhavar Thirunal is a harvest festival celebrated in Tamil Nadu, India,
+        as part of the Pongal festivities. It is dedicated to honoring farmers
+        (uzhavar) and their contribution to agriculture. Uzhavar Thirunal usually
+        falls on January 16th or 17th each year.
+        https://en.wikipedia.org/wiki/Pongal_(festival)#Uzhavar_Thirunal
+        """
+        return self._add_hindu_calendar_holiday(
+            name, self._hindu_calendar.pongal_date(self._year), days_delta=+2
+        )
+
     def _add_vaisakhi(self, name) -> Optional[date]:
         """
         Add Vaisakhi.
diff --git a/holidays/locale/en_IN/LC_MESSAGES/IN.po b/holidays/locale/en_IN/LC_MESSAGES/IN.po
index 7e321e12..fe3deb1e 100644
--- a/holidays/locale/en_IN/LC_MESSAGES/IN.po
+++ b/holidays/locale/en_IN/LC_MESSAGES/IN.po
@@ -14,7 +14,7 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: Holidays 0.69\n"
+"Project-Id-Version: Holidays 0.72\n"
 "POT-Creation-Date: 2025-02-28 02:31+0530\n"
 "PO-Revision-Date: 2025-03-01 15:11+0530\n"
 "Last-Translator: Ankush Kapoor <work.ankushkapoor1626@gmail.com>\n"
@@ -306,3 +306,11 @@ msgstr ""
 #. Buddha Purnima.
 msgid "Buddha Purnima"
 msgstr ""
+
+#. Thiruvalluvar Day / Mattu Pongal.
+msgid "Thiruvalluvar Day / Mattu Pongal"
+msgstr ""
+
+#. Uzhavar Thirunal.
+msgid "Uzhavar Thirunal"
+msgstr ""
diff --git a/holidays/locale/en_US/LC_MESSAGES/IN.po b/holidays/locale/en_US/LC_MESSAGES/IN.po
index 2924b9f8..61671090 100644
--- a/holidays/locale/en_US/LC_MESSAGES/IN.po
+++ b/holidays/locale/en_US/LC_MESSAGES/IN.po
@@ -14,7 +14,7 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: Holidays 0.69\n"
+"Project-Id-Version: Holidays 0.72\n"
 "POT-Creation-Date: 2025-03-02 12:31+0530\n"
 "PO-Revision-Date: 2025-03-02 12:54+0530\n"
 "Last-Translator: Ankush Kapoor <work.ankushkapoor1626@gmail.com>\n"
@@ -307,3 +307,11 @@ msgstr "Magh Bihu"
 #. Buddha Purnima.
 msgid "Buddha Purnima"
 msgstr "Buddha Purnima"
+
+#. Thiruvalluvar Day / Mattu Pongal.
+msgid "Thiruvalluvar Day / Mattu Pongal"
+msgstr "Thiruvalluvar Day / Mattu Pongal"
+
+#. Uzhavar Thirunal.
+msgid "Uzhavar Thirunal"
+msgstr "Uzhavar Thirunal"
diff --git a/holidays/locale/hi/LC_MESSAGES/IN.po b/holidays/locale/hi/LC_MESSAGES/IN.po
index 86b400c3..dd28b206 100644
--- a/holidays/locale/hi/LC_MESSAGES/IN.po
+++ b/holidays/locale/hi/LC_MESSAGES/IN.po
@@ -14,7 +14,7 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: Holidays 0.69\n"
+"Project-Id-Version: Holidays 0.72\n"
 "POT-Creation-Date: 2025-02-28 01:24+0530\n"
 "PO-Revision-Date: 2025-03-01 15:11+0530\n"
 "Last-Translator: Ankush Kapoor <work.ankushkapoor1626@gmail.com>\n"
@@ -306,3 +306,11 @@ msgstr "माघ बिहू"
 #. Buddha Purnima.
 msgid "Buddha Purnima"
 msgstr "बुद्ध पूर्णिमा"
+
+#. Thiruvalluvar Day / Mattu Pongal.
+msgid "Thiruvalluvar Day / Mattu Pongal"
+msgstr "तिरुवल्लुवर दिवस / मट्टू पोंगल"
+
+#. Uzhavar Thirunal.
+msgid "Uzhavar Thirunal"
+msgstr "उझावर थिरुनल"


Test patch:
diff --git a/tests/countries/test_india.py b/tests/countries/test_india.py
index 07dc3624..2dd385b4 100644
--- a/tests/countries/test_india.py
+++ b/tests/countries/test_india.py
@@ -147,6 +147,8 @@ class TestIndia(CommonCountryTests, TestCase):
             ),
             "TN": (
                 "2018-01-14",
+                "2018-01-15",
+                "2018-01-16",
                 "2018-04-14",
             ),
             "TS": (
@@ -393,6 +395,32 @@ class TestIndia(CommonCountryTests, TestCase):
             else:
                 self.assertNoHolidayName(name, India(subdiv=subdiv), dt)
 
+        dt = (
+            "2001-01-15",
+            "2010-01-15",
+            "2025-01-15",
+            "2035-01-16",
+        )
+        name = "Thiruvalluvar Day / Mattu Pongal"
+        for subdiv in India.subdivisions:
+            if subdiv in {"TN"}:
+                self.assertHolidayName(name, India(subdiv=subdiv), dt)
+            else:
+                self.assertNoHolidayName(name, India(subdiv=subdiv), dt)
+
+        dt = (
+            "2001-01-16",
+            "2010-01-16",
+            "2025-01-16",
+            "2035-01-17",
+        )
+        name = "Uzhavar Thirunal"
+        for subdiv in India.subdivisions:
+            if subdiv in {"TN"}:
+                self.assertHolidayName(name, India(subdiv=subdiv), dt)
+            else:
+                self.assertNoHolidayName(name, India(subdiv=subdiv), dt)
+
     def test_ranged_optional_holidays(self):
         opt_holidays = India(categories=OPTIONAL)
 
@@ -501,6 +529,8 @@ class TestIndia(CommonCountryTests, TestCase):
         self.assertLocalizedHolidays(
             ("2018-01-13", "Lohri"),
             ("2018-01-14", "Magh Bihu; Makar Sankranti; Pongal; Uttarayan"),
+            ("2018-01-15", "Thiruvalluvar Day / Mattu Pongal"),
+            ("2018-01-16", "Uzhavar Thirunal"),
             ("2018-01-24", "UP Formation Day"),
             ("2018-01-26", "Republic Day"),
             ("2018-02-13", "Maha Shivaratri"),
@@ -567,6 +597,8 @@ class TestIndia(CommonCountryTests, TestCase):
             "hi",
             ("2018-01-13", "लोहड़ी"),
             ("2018-01-14", "उत्तरायण; पोंगल; मकर संक्रांति; माघ बिहू"),
+            ("2018-01-15", "तिरुवल्लुवर दिवस / मट्टू पोंगल"),
+            ("2018-01-16", "उझावर थिरुनल"),
             ("2018-01-24", "यूपी स्थापना दिवस"),
             ("2018-01-26", "गणतंत्र दिवस"),
             ("2018-02-13", "महाशिवरात्रि"),
@@ -628,6 +660,8 @@ class TestIndia(CommonCountryTests, TestCase):
             "en_US",
             ("2018-01-13", "Lohri"),
             ("2018-01-14", "Magh Bihu; Makar Sankranti; Pongal; Uttarayan"),
+            ("2018-01-15", "Thiruvalluvar Day / Mattu Pongal"),
+            ("2018-01-16", "Uzhavar Thirunal"),
             ("2018-01-24", "UP Formation Day"),
             ("2018-01-26", "Republic Day"),
             ("2018-02-13", "Maha Shivaratri"),