Repository: vacanza/holidays (python)

Issue:
Add Niue holidays
URLs:
- https://en.wikipedia.org/wiki/Public_holidays_in_Niue

Pull request:
Add Niue holidays
<!--
  Thanks for contributing to holidays!
-->

## Proposed change

<!--
  Describe the big picture of your changes.
  Don't forget to link your PR to an existing issue if any.
-->

Added support for NU holidays. 
Closes #2667 

## Type of change

<!--
  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.
-->

- [x] New country/market holidays support (thank you!)
- [ ] 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/README.md b/README.md
index 03931878..b23b3d33 100644
--- a/README.md
+++ b/README.md
@@ -105,7 +105,7 @@ and detailed information.
 
 ## Available Countries
 
-We currently support 220 country codes. The standard way to refer to a country is by using its [ISO
+We currently support 221 country codes. The standard way to refer to a country is by using its [ISO
 3166-1 alpha-2 code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes), the same used
 for domain names, and for a subdivision its [ISO 3166-2
 code](https://en.wikipedia.org/wiki/ISO_3166-2). Some countries have common or foreign names or
@@ -1162,6 +1162,13 @@ any) in brackets, available languages and additional holiday categories. All cou
 <td></td>
 </tr>
 <tr>
+<td>Niue</td>
+<td>NU</td>
+<td></td>
+<td><strong>en_NU</strong>, en_US</td>
+<td></td>
+</tr>
+<tr>
 <td>Norfolk Island</td>
 <td>NF</td>
 <td></td>
diff --git a/holidays/countries/__init__.py b/holidays/countries/__init__.py
index 4acba245..067e4b6b 100644
--- a/holidays/countries/__init__.py
+++ b/holidays/countries/__init__.py
@@ -162,6 +162,7 @@ from holidays.countries.new_zealand import NewZealand, NZ, NZL
 from holidays.countries.nicaragua import Nicaragua, NI, NIC
 from holidays.countries.niger import Niger, NE, NER
 from holidays.countries.nigeria import Nigeria, NG, NGA
+from holidays.countries.niue import Niue, NU, NIU
 from holidays.countries.norfolk_island import NorfolkIsland, NF, NFK
 from holidays.countries.north_macedonia import NorthMacedonia, MK, MKD
 from holidays.countries.northern_mariana_islands import NorthernMarianaIslands, MP, MNP, HolidaysMP
diff --git a/holidays/countries/niue.py b/holidays/countries/niue.py
new file mode 100644
index 00000000..6a92e55c
--- /dev/null
+++ b/holidays/countries/niue.py
@@ -0,0 +1,115 @@
+#  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: Vacanza Team and individual contributors (see CONTRIBUTORS file)
+#           dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
+#           ryanss <ryanssdev@icloud.com> (c) 2014-2017
+#  Website: https://github.com/vacanza/holidays
+#  License: MIT (see LICENSE file)
+
+from gettext import gettext as tr
+
+from holidays.calendars.gregorian import SEP
+from holidays.groups import ChristianHolidays, InternationalHolidays, StaticHolidays
+from holidays.observed_holiday_base import (
+    ObservedHolidayBase,
+    SAT_SUN_TO_NEXT_MON,
+    SAT_SUN_TO_NEXT_MON_TUE,
+)
+
+
+class Niue(ObservedHolidayBase, ChristianHolidays, InternationalHolidays, StaticHolidays):
+    """Niue holidays.
+
+    References:
+        * <https://en.wikipedia.org/wiki/Public_holidays_in_Niue>
+        * <https://en.wikipedia.org/wiki/Niue_Constitution_Act>
+        * [Public Holidays Ordinance 1961](https://web.archive.org/web/20250102100637/http://www.paclii.org/nu/legis/num_act/nipho1961314.pdf)
+        * <https://web.archive.org/web/20250223114854/https://niuepocketguide.com/public-holidays-in-niue-other-important-dates/>
+        * [2021/2022 Public Holidays](https://web.archive.org/web/20250509105501/https://www.gov.nu/media/pages/information/1018c58017-1725838374/4nov2021-circular.pdf)
+        * [2025 Good Friday & Easter Monday and Anzac Day](https://web.archive.org/web/20250719195126/https://www.gov.nu/media/pages/gazette/3e02b3aa84-1746400484/official-psc-circular-easter-anzac-holiday.pdf)
+        * [2025 King's Birthday](https://web.archive.org/web/20250719195301/https://www.gov.nu/media/pages/public-service-circulars/3b9f44b6a0-1748573974/king-s-birthday-public-holiday-2025-circular.pdf)
+        * <http://archive.today/2025.07.14-145535/https://www.wipo.int/wipolex/en/text/427817>
+    """
+
+    country = "NU"
+    default_language = "en_NU"
+    # %s observed.
+    observed_label = tr("%s (observed)")
+    # Public Holidays Ordinance 1961.
+    start_year = 1962
+    supported_languages = ("en_NU", "en_US")
+
+    def __init__(self, *args, **kwargs):
+        ChristianHolidays.__init__(self)
+        InternationalHolidays.__init__(self)
+        StaticHolidays.__init__(self, cls=NiueStaticHolidays)
+        kwargs.setdefault("observed_rule", SAT_SUN_TO_NEXT_MON_TUE)
+        super().__init__(*args, **kwargs)
+
+    def _populate_public_holidays(self):
+        # New Year's Day.
+        self._add_observed(self._add_new_years_day(tr("New Year's Day")))
+
+        # Takai Commission Holiday.
+        self._add_observed(self._add_new_years_day_two(tr("Takai Commission Holiday")))
+
+        # Good Friday.
+        self._add_good_friday(tr("Good Friday"))
+
+        # Easter Monday.
+        self._add_easter_monday(tr("Easter Monday"))
+
+        # ANZAC Day.
+        self._add_observed(self._add_anzac_day(tr("ANZAC Day")), rule=SAT_SUN_TO_NEXT_MON)
+
+        self._add_holiday_1st_mon_of_jun(
+            # King's Birthday.
+            tr("King's Birthday")
+            if self._year >= 2023
+            # Queen's Birthday.
+            else tr("Queen's Birthday")
+        )
+
+        if self._year >= 1974:
+            # Constitution Day.
+            self._add_observed(self._add_holiday_oct_19(tr("Constitution Day")))
+
+            # Constitution Day Holiday.
+            self._add_observed(self._add_holiday_oct_20(tr("Constitution Day Holiday")))
+        else:
+            # Annexation Day.
+            self._add_holiday_3rd_mon_of_oct(tr("Annexation Day"))
+
+        # Peniamina Gospel Day.
+        self._add_holiday_4th_mon_of_oct(tr("Peniamina Gospel Day"))
+
+        # Christmas Day.
+        self._add_observed(self._add_christmas_day(tr("Christmas Day")))
+
+        # Boxing Day.
+        self._add_observed(self._add_christmas_day_two(tr("Boxing Day")))
+
+
+class NU(Niue):
+    pass
+
+
+class NIU(Niue):
+    pass
+
+
+class NiueStaticHolidays:
+    """Niue special holidays.
+
+    References:
+        * [Queen Elizabeth II's Funeral](https://web.archive.org/web/20250617174022/https://tvniue.com/2022/09/premier-will-attend-hm-the-queens-funeral-while-monday-19th-is-declared-one-off-public-holiday/)
+    """
+
+    special_public_holidays = {
+        # Queen Elizabeth II's Funeral.
+        2022: (SEP, 19, tr("Queen Elizabeth II's Funeral")),
+    }
diff --git a/holidays/locale/en_NU/LC_MESSAGES/NU.po b/holidays/locale/en_NU/LC_MESSAGES/NU.po
new file mode 100644
index 00000000..b4cb42ed
--- /dev/null
+++ b/holidays/locale/en_NU/LC_MESSAGES/NU.po
@@ -0,0 +1,88 @@
+#  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: Vacanza Team and individual contributors (see CONTRIBUTORS file)
+#           dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
+#           ryanss <ryanssdev@icloud.com> (c) 2014-2017
+#  Website: https://github.com/vacanza/holidays
+#  License: MIT (see LICENSE file)
+#
+# Niue holidays.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Holidays 0.77\n"
+"POT-Creation-Date: 2025-07-19 13:54+0000\n"
+"PO-Revision-Date: 2025-07-19 13:54+0000\n"
+"Last-Translator: Abheelash Mishra <abheelashdev@gmail.com>\n"
+"Language-Team: Holidays Localization Team\n"
+"Language: en_NU\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Lingva 5.0.6\n"
+"X-Source-Language: en_NU\n"
+
+#. %s observed.
+#, c-format
+msgid "%s (observed)"
+msgstr ""
+
+#. New Year's Day.
+msgid "New Year's Day"
+msgstr ""
+
+#. Takai Commission Holiday.
+msgid "Takai Commission Holiday"
+msgstr ""
+
+#. Good Friday.
+msgid "Good Friday"
+msgstr ""
+
+#. Easter Monday.
+msgid "Easter Monday"
+msgstr ""
+
+#. ANZAC Day.
+msgid "ANZAC Day"
+msgstr ""
+
+#. King's Birthday.
+msgid "King's Birthday"
+msgstr ""
+
+#. Queen's Birthday.
+msgid "Queen's Birthday"
+msgstr ""
+
+#. Constitution Day.
+msgid "Constitution Day"
+msgstr ""
+
+#. Constitution Day Holiday.
+msgid "Constitution Day Holiday"
+msgstr ""
+
+#. Annexation Day.
+msgid "Annexation Day"
+msgstr ""
+
+#. Peniamina Gospel Day.
+msgid "Peniamina Gospel Day"
+msgstr ""
+
+#. Christmas Day.
+msgid "Christmas Day"
+msgstr ""
+
+#. Boxing Day.
+msgid "Boxing Day"
+msgstr ""
+
+#. Queen Elizabeth II's Funeral.
+msgid "Queen Elizabeth II's Funeral"
+msgstr ""
diff --git a/holidays/locale/en_US/LC_MESSAGES/NU.po b/holidays/locale/en_US/LC_MESSAGES/NU.po
new file mode 100644
index 00000000..2320a562
--- /dev/null
+++ b/holidays/locale/en_US/LC_MESSAGES/NU.po
@@ -0,0 +1,88 @@
+#  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: Vacanza Team and individual contributors (see CONTRIBUTORS file)
+#           dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
+#           ryanss <ryanssdev@icloud.com> (c) 2014-2017
+#  Website: https://github.com/vacanza/holidays
+#  License: MIT (see LICENSE file)
+#
+# Niue holidays en_US localization.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Holidays 0.77\n"
+"POT-Creation-Date: 2025-07-19 13:54+0000\n"
+"PO-Revision-Date: 2025-07-19 13:54+0000\n"
+"Last-Translator: Abheelash Mishra <abheelashdev@gmail.com>\n"
+"Language-Team: Holidays Localization Team\n"
+"Language: en_US\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Lingva 5.0.6\n"
+"X-Source-Language: en_NU\n"
+
+#. %s observed.
+#, c-format
+msgid "%s (observed)"
+msgstr "%s (observed)"
+
+#. New Year's Day.
+msgid "New Year's Day"
+msgstr "New Year's Day"
+
+#. Takai Commission Holiday.
+msgid "Takai Commission Holiday"
+msgstr "Takai Commission Holiday"
+
+#. Good Friday.
+msgid "Good Friday"
+msgstr "Good Friday"
+
+#. Easter Monday.
+msgid "Easter Monday"
+msgstr "Easter Monday"
+
+#. ANZAC Day.
+msgid "ANZAC Day"
+msgstr "ANZAC Day"
+
+#. King's Birthday.
+msgid "King's Birthday"
+msgstr "King's Birthday"
+
+#. Queen's Birthday.
+msgid "Queen's Birthday"
+msgstr "Queen's Birthday"
+
+#. Constitution Day.
+msgid "Constitution Day"
+msgstr "Constitution Day"
+
+#. Constitution Day Holiday.
+msgid "Constitution Day Holiday"
+msgstr "Constitution Day Holiday"
+
+#. Annexation Day.
+msgid "Annexation Day"
+msgstr "Annexation Day"
+
+#. Peniamina Gospel Day.
+msgid "Peniamina Gospel Day"
+msgstr "Peniamina Gospel Day"
+
+#. Christmas Day.
+msgid "Christmas Day"
+msgstr "Christmas Day"
+
+#. Boxing Day.
+msgid "Boxing Day"
+msgstr "Boxing Day"
+
+#. Queen Elizabeth II's Funeral.
+msgid "Queen Elizabeth II's Funeral"
+msgstr "Queen Elizabeth II's Funeral"
diff --git a/holidays/registry.py b/holidays/registry.py
index abeb75af..15a306a4 100644
--- a/holidays/registry.py
+++ b/holidays/registry.py
@@ -165,6 +165,7 @@ COUNTRIES: RegistryDict = {
     "nicaragua": ("Nicaragua", "NI", "NIC"),
     "niger": ("Niger", "NE", "NER"),
     "nigeria": ("Nigeria", "NG", "NGA"),
+    "niue": ("Niue", "NU", "NIU"),
     "norfolk_island": ("NorfolkIsland", "NF", "NFK"),
     "north_macedonia": ("NorthMacedonia", "MK", "MKD"),
     "northern_mariana_islands": ("NorthernMarianaIslands", "MP", "MNP", "HolidaysMP"),


Test patch:
diff --git a/tests/countries/test_niue.py b/tests/countries/test_niue.py
new file mode 100644
index 00000000..78fa5ff7
--- /dev/null
+++ b/tests/countries/test_niue.py
@@ -0,0 +1,232 @@
+#  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: Vacanza Team and individual contributors (see CONTRIBUTORS file)
+#           dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
+#           ryanss <ryanssdev@icloud.com> (c) 2014-2017
+#  Website: https://github.com/vacanza/holidays
+#  License: MIT (see LICENSE file)
+
+from unittest import TestCase
+
+from holidays.countries.niue import Niue, NU, NIU
+from tests.common import CommonCountryTests
+
+
+class TestNiue(CommonCountryTests, TestCase):
+    @classmethod
+    def setUpClass(cls):
+        years = range(1962, 2050)
+        super().setUpClass(Niue, years=years, years_non_observed=years)
+
+    def test_country_aliases(self):
+        self.assertAliases(Niue, NU, NIU)
+
+    def test_no_holidays(self):
+        self.assertNoHolidays(Niue(years=1961))
+
+    def test_special_holidays(self):
+        self.assertHoliday(
+            "2022-09-19",
+        )
+
+    def test_new_years_day(self):
+        name = "New Year's Day"
+        self.assertHolidayName(name, (f"{year}-01-01" for year in range(1962, 2050)))
+        obs_dt = (
+            "2011-01-03",
+            "2012-01-03",
+            "2017-01-03",
+            "2022-01-03",
+            "2023-01-03",
+        )
+        self.assertHolidayName(f"{name} (observed)", obs_dt)
+        self.assertNoNonObservedHoliday(obs_dt)
+
+    def test_takai_commission_holiday(self):
+        name = "Takai Commission Holiday"
+        self.assertHolidayName(name, (f"{year}-01-02" for year in range(1962, 2050)))
+        obs_dt = (
+            "2011-01-04",
+            "2016-01-04",
+            "2021-01-04",
+            "2022-01-04",
+        )
+        self.assertHolidayName(f"{name} (observed)", obs_dt)
+        self.assertNoNonObservedHoliday(obs_dt)
+
+    def test_good_friday(self):
+        name = "Good Friday"
+        self.assertHolidayName(
+            name,
+            "2020-04-10",
+            "2021-04-02",
+            "2022-04-15",
+            "2023-04-07",
+            "2024-03-29",
+            "2025-04-18",
+        )
+        self.assertHolidayName(name, range(1962, 2050))
+
+    def test_easter_monday(self):
+        name = "Easter Monday"
+        self.assertHolidayName(
+            name,
+            "2020-04-13",
+            "2021-04-05",
+            "2022-04-18",
+            "2023-04-10",
+            "2024-04-01",
+            "2025-04-21",
+        )
+        self.assertHolidayName(name, range(1962, 2050))
+
+    def test_anzac_day(self):
+        name = "ANZAC Day"
+        self.assertHolidayName(name, (f"{year}-04-25" for year in range(1962, 2050)))
+        obs_dt = (
+            "2009-04-27",
+            "2010-04-26",
+            "2015-04-27",
+            "2020-04-27",
+            "2021-04-26",
+        )
+        self.assertHolidayName(f"{name} (observed)", obs_dt)
+        self.assertNoNonObservedHoliday(obs_dt)
+
+    def test_queens_birthday(self):
+        name = "Queen's Birthday"
+        self.assertHolidayName(
+            name,
+            "2018-06-04",
+            "2019-06-03",
+            "2020-06-01",
+            "2021-06-07",
+            "2022-06-06",
+        )
+        self.assertHolidayName(name, range(1962, 2023))
+        self.assertNoHolidayName(name, range(2023, 2050))
+
+    def test_kings_birthday(self):
+        name = "King's Birthday"
+        self.assertHolidayName(
+            name,
+            "2023-06-05",
+            "2024-06-03",
+            "2025-06-02",
+        )
+        self.assertHolidayName(name, range(2023, 2050))
+        self.assertNoHolidayName(name, range(1962, 2023))
+
+    def test_constitution_day(self):
+        name = "Constitution Day"
+        self.assertHolidayName(name, (f"{year}-10-19" for year in range(1974, 2050)))
+        self.assertNoHolidayName(name, range(1962, 1974))
+        obs_dt = (
+            "2013-10-21",
+            "2014-10-21",
+            "2019-10-21",
+            "2024-10-21",
+            "2025-10-21",
+        )
+        self.assertHolidayName(f"{name} (observed)", obs_dt)
+        self.assertNoNonObservedHoliday(obs_dt)
+
+    def test_constitution_day_holiday(self):
+        name = "Constitution Day Holiday"
+        self.assertHolidayName(name, (f"{year}-10-20" for year in range(1974, 2050)))
+        self.assertNoHolidayName(name, range(1962, 1974))
+        obs_dt = (
+            "2013-10-22",
+            "2019-10-22",
+            "2024-10-22",
+        )
+        self.assertHolidayName(f"{name} (observed)", obs_dt)
+        self.assertNoNonObservedHoliday(obs_dt)
+
+    def test_annexation_day(self):
+        name = "Annexation Day"
+        self.assertHolidayName(
+            name,
+            "1969-10-20",
+            "1970-10-19",
+            "1971-10-18",
+            "1972-10-16",
+            "1973-10-15",
+        )
+        self.assertHolidayName(name, range(1962, 1974))
+        self.assertNoHolidayName(name, range(1974, 2050))
+
+    def test_peniamina_gospel_day(self):
+        name = "Peniamina Gospel Day"
+        self.assertHolidayName(
+            name,
+            "2020-10-26",
+            "2021-10-25",
+            "2022-10-24",
+            "2023-10-23",
+            "2024-10-28",
+            "2025-10-27",
+        )
+        self.assertHolidayName(name, range(1962, 2050))
+
+    def test_christmas_day(self):
+        name = "Christmas Day"
+        self.assertHolidayName(name, (f"{year}-12-25" for year in range(1962, 2050)))
+        obs_dt = (
+            "2010-12-27",
+            "2011-12-27",
+            "2016-12-27",
+            "2021-12-27",
+            "2022-12-27",
+        )
+        self.assertHolidayName(f"{name} (observed)", obs_dt)
+        self.assertNoNonObservedHoliday(obs_dt)
+
+    def test_boxing_day(self):
+        name = "Boxing Day"
+        self.assertHolidayName(name, (f"{year}-12-26" for year in range(1962, 2050)))
+        obs_dt = (
+            "2010-12-28",
+            "2015-12-28",
+            "2020-12-28",
+            "2021-12-28",
+        )
+        self.assertHolidayName(f"{name} (observed)", obs_dt)
+        self.assertNoNonObservedHoliday(obs_dt)
+
+    def test_l10n_default(self):
+        self.assertLocalizedHolidays(
+            ("2025-01-01", "New Year's Day"),
+            ("2025-01-02", "Takai Commission Holiday"),
+            ("2025-04-18", "Good Friday"),
+            ("2025-04-21", "Easter Monday"),
+            ("2025-04-25", "ANZAC Day"),
+            ("2025-06-02", "King's Birthday"),
+            ("2025-10-19", "Constitution Day"),
+            ("2025-10-20", "Constitution Day Holiday"),
+            ("2025-10-21", "Constitution Day (observed)"),
+            ("2025-10-27", "Peniamina Gospel Day"),
+            ("2025-12-25", "Christmas Day"),
+            ("2025-12-26", "Boxing Day"),
+        )
+
+    def test_l10n_en_us(self):
+        self.assertLocalizedHolidays(
+            "en_US",
+            ("2025-01-01", "New Year's Day"),
+            ("2025-01-02", "Takai Commission Holiday"),
+            ("2025-04-18", "Good Friday"),
+            ("2025-04-21", "Easter Monday"),
+            ("2025-04-25", "ANZAC Day"),
+            ("2025-06-02", "King's Birthday"),
+            ("2025-10-19", "Constitution Day"),
+            ("2025-10-20", "Constitution Day Holiday"),
+            ("2025-10-21", "Constitution Day (observed)"),
+            ("2025-10-27", "Peniamina Gospel Day"),
+            ("2025-12-25", "Christmas Day"),
+            ("2025-12-26", "Boxing Day"),
+        )