Repository: vacanza/python-holidays

Issue:
Add Ghana holidays
Links:
  - https://en.wikipedia.org/wiki/Public_holidays_in_Ghana
  - https://www.timeanddate.com/holidays/ghana/
  - https://www.mint.gov.gh/statutory-public-holidays/
  - https://www.bog.gov.gh/official-holidays/


Discussion:
I can pick this up if it's still available

Resolving patch:
diff --git a/holidays/countries/__init__.py b/holidays/countries/__init__.py
--- a/holidays/countries/__init__.py
+++ b/holidays/countries/__init__.py
@@ -64,6 +64,7 @@
 from .gabon import Gabon, GA, GAB
 from .georgia import Georgia, GE, GEO
 from .germany import Germany, DE, DEU
+from .ghana import Ghana, GH, GHA
 from .greece import Greece, GR, GRC
 from .guam import Guam, GU, GUM, HolidaysGU
 from .guatemala import Guatemala, GT, GUA
diff --git a/holidays/countries/ghana.py b/holidays/countries/ghana.py
new file mode 100644
--- /dev/null
+++ b/holidays/countries/ghana.py
@@ -0,0 +1,97 @@
+#  python-holidays
+#  ---------------
+#  A fast, efficient Python library for generating country, province and state
+#  specific sets of holidays on the fly. It aims to make determining whether a
+#  specific date is a holiday as fast and flexible as possible.
+#
+#  Authors: dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
+#           ryanss <ryanssdev@icloud.com> (c) 2014-2017
+#  Website: https://github.com/dr-prodigy/python-holidays
+#  License: MIT (see LICENSE file)
+
+from holidays.groups import ChristianHolidays, InternationalHolidays, IslamicHolidays
+from holidays.observed_holiday_base import (
+    ObservedHolidayBase,
+    SAT_SUN_TO_NEXT_MON,
+    SAT_SUN_TO_NEXT_MON_TUE,
+)
+
+
+class Ghana(ObservedHolidayBase, ChristianHolidays, InternationalHolidays, IslamicHolidays):
+    """
+    https://www.mint.gov.gh/statutory-public-holidays/
+    https://en.wikipedia.org/wiki/Public_holidays_in_Ghana
+    """
+
+    country = "GH"
+    estimated_label = "%s (estimated)"
+    observed_label = "%s (observed)"
+    observed_estimated_label = "%s (observed, estimated)"
+
+    def __init__(self, *args, **kwargs):
+        ChristianHolidays.__init__(self)
+        InternationalHolidays.__init__(self)
+        IslamicHolidays.__init__(self)
+        kwargs.setdefault("observed_rule", SAT_SUN_TO_NEXT_MON)
+        super().__init__(*args, **kwargs)
+
+    def _populate_public_holidays(self):
+        # Holidays observed since 1957
+        if self._year <= 1956:
+            return None
+
+        # New Year's Day
+        self._add_observed(self._add_new_years_day("New Year's Day"))
+
+        # Constitution Day
+        if self._year >= 2019:
+            self._add_observed(self._add_holiday_jan_7("Constitution Day"))
+
+        # Independence Day
+        self._add_observed(self._add_holiday_mar_6("Independence Day"))
+
+        # Good Friday
+        self._add_good_friday("Good Friday")
+
+        # Easter Monday
+        self._add_easter_monday("Easter Monday")
+
+        # May Day(Workers' Day)
+        self._add_observed(self._add_labor_day("May Day"))
+
+        # Eid al-Fitr
+        for dt in self._add_eid_al_fitr_day("Eid ul-Fitr"):
+            self._add_observed(dt)
+
+        # Eid al-Adha
+        for dt in self._add_eid_al_adha_day("Eid ul-Adha"):
+            self._add_observed(dt)
+
+        # Founders' Day
+        if self._year >= 2019:
+            self._add_observed(self._add_holiday_aug_4("Founders' Day"))
+
+        # Kwame Nkrumah Memorial Day / Founder's Day
+        if self._year >= 2009:
+            self._add_observed(
+                self._add_holiday_sep_21(
+                    "Kwame Nkrumah Memorial Day" if self._year >= 2019 else "Founder's Day"
+                )
+            )
+
+        # Farmer's Day
+        self._add_holiday_1st_fri_of_dec("Farmer's Day")
+
+        # Christmas Day
+        self._add_observed(self._add_christmas_day("Christmas Day"), rule=SAT_SUN_TO_NEXT_MON_TUE)
+
+        # Boxing Day
+        self._add_observed(self._add_christmas_day_two("Boxing Day"), rule=SAT_SUN_TO_NEXT_MON_TUE)
+
+
+class GH(Ghana):
+    pass
+
+
+class GHA(Ghana):
+    pass
diff --git a/holidays/registry.py b/holidays/registry.py
--- a/holidays/registry.py
+++ b/holidays/registry.py
@@ -70,6 +70,7 @@
     "gabon": ("Gabon", "GA", "GAB"),
     "georgia": ("Georgia", "GE", "GEO"),
     "germany": ("Germany", "DE", "DEU"),
+    "ghana": ("Ghana", "GH", "GHA"),
     "greece": ("Greece", "GR", "GRC"),
     "guam": ("Guam", "GU", "GUM", "HolidaysGU"),
     "guatemala": ("Guatemala", "GT", "GUA"),


Test patch:
diff --git a/tests/countries/test_ghana.py b/tests/countries/test_ghana.py
new file mode 100644
--- /dev/null
+++ b/tests/countries/test_ghana.py
@@ -0,0 +1,106 @@
+#  python-holidays
+#  ---------------
+#  A fast, efficient Python library for generating country, province and state
+#  specific sets of holidays on the fly. It aims to make determining whether a
+#  specific date is a holiday as fast and flexible as possible.
+#
+#  Authors: dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
+#           ryanss <ryanssdev@icloud.com> (c) 2014-2017
+#  Website: https://github.com/dr-prodigy/python-holidays
+#  License: MIT (see LICENSE file)
+
+from unittest import TestCase
+
+from holidays.countries.ghana import Ghana, GH, GHA
+from tests.common import CommonCountryTests
+
+
+class TestGhana(CommonCountryTests, TestCase):
+    @classmethod
+    def setUpClass(cls):
+        super().setUpClass(Ghana, years=range(1957, 2050))
+
+    def test_country_aliases(self):
+        self.assertAliases(Ghana, GH, GHA)
+
+    def test_no_holidays(self):
+        self.assertNoHolidays(Ghana(years=1956))
+
+    def test_new_year_day(self):
+        self.assertHoliday(f"{year}-01-01" for year in range(1957, 2050))
+
+    def test_constitution_day(self):
+        self.assertHoliday(f"{year}-01-07" for year in range(2019, 2050))
+        self.assertNoHoliday(f"{year}-01-07" for year in range(1957, 2019))
+        self.assertNoHolidayName("Constitution Day", range(1957, 2019))
+
+    def test_founders_day(self):
+        self.assertHoliday(f"{year}-08-04" for year in range(2019, 2050))
+
+    def test_independence_day(self):
+        self.assertHoliday(f"{year}-03-06" for year in range(1957, 2050))
+
+    def test_farmers_day(self):  # 1st Friday of December
+        self.assertHolidayName(
+            "Farmer's Day",
+            "2023-12-01",
+            "2024-12-06",
+            "2025-12-05",
+            "2026-12-04",
+            "2027-12-03",
+            "2028-12-01",
+            "2029-12-07",
+            "2030-12-06",
+        )
+
+    def test_eid_ul_fitr(self):
+        self.assertHolidayName(
+            "Eid ul-Fitr (estimated)",
+            "2020-05-24",
+            "2021-05-13",
+            "2022-05-02",
+            "2023-04-21",
+            "2024-04-10",
+        )
+
+    def test_2023(self):
+        self.assertHolidays(
+            Ghana(years=2023),
+            ("2023-01-01", "New Year's Day"),
+            ("2023-01-02", "New Year's Day (observed)"),
+            ("2023-01-07", "Constitution Day"),
+            ("2023-01-09", "Constitution Day (observed)"),
+            ("2023-03-06", "Independence Day"),
+            ("2023-04-07", "Good Friday"),
+            ("2023-04-10", "Easter Monday"),
+            ("2023-05-01", "May Day"),
+            ("2023-04-21", "Eid ul-Fitr (estimated)"),
+            ("2023-06-28", "Eid ul-Adha (estimated)"),
+            ("2023-08-04", "Founders' Day"),
+            ("2023-09-21", "Kwame Nkrumah Memorial Day"),
+            ("2023-12-01", "Farmer's Day"),
+            ("2023-12-25", "Christmas Day"),
+            ("2023-12-26", "Boxing Day"),
+        )
+
+    def test_2024(self):
+        self.assertHolidays(
+            Ghana(years=2024),
+            ("2024-01-01", "New Year's Day"),
+            ("2024-01-07", "Constitution Day"),
+            ("2024-01-08", "Constitution Day (observed)"),
+            ("2024-03-06", "Independence Day"),
+            ("2024-03-29", "Good Friday"),
+            ("2024-04-01", "Easter Monday"),
+            ("2024-05-01", "May Day"),
+            ("2024-04-10", "Eid ul-Fitr (estimated)"),
+            ("2024-06-16", "Eid ul-Adha (estimated)"),
+            ("2024-06-17", "Eid ul-Adha (observed, estimated)"),
+            ("2024-08-04", "Founders' Day"),
+            ("2024-08-05", "Founders' Day (observed)"),
+            ("2024-09-21", "Kwame Nkrumah Memorial Day"),
+            ("2024-09-23", "Kwame Nkrumah Memorial Day (observed)"),
+            ("2024-12-06", "Farmer's Day"),
+            ("2024-12-25", "Christmas Day"),
+            ("2024-12-26", "Boxing Day"),
+        )