Repository: vacanza/holidays (python)

Issue:
Add Gibraltar holidays
URLs:
- https://en.wikipedia.org/wiki/Public_holidays_in_Gibraltar

Pull request:
Add Gibraltar 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.
-->

(I'm back within 24 hours of assignment :slightly_smiling_face:)
~~There are 2 issues which I'd like to address here.~~ 

1. ~~Some WM links are not functioning because of JSViewer for PDF used by the Government's website. (They're not displaying the PDF inside the JSViewer)~~
2. ~~There is a public holiday called "Workers' Memorial Holiday" which started in 2012 but it doesn't have a fixed pattern. It falls towards the end of April but I couldn't generalize the pattern so I've left it as of now. The sites not providing written rules for Observed Holidays and having Observed Holidays makes it even worse, for example, in 2013, it says that the previous Friday was off for that Holiday but the reason wasn't specified. There were 2 possibilities there:~~ 
- ~~May Day was on Monday so the Observed Holiday was shifted to previous Friday~~
- ~~It was already supposed to go to previous Friday~~

~~Because of all these reasons, I've currently left so I can hear from maintainers over what to do.~~ => **FIXED**

Resolves #2659 

## 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 19b71bfa..d5e47b58 100644
--- a/README.md
+++ b/README.md
@@ -105,7 +105,7 @@ and detailed information.
 
 ## Available Countries
 
-We currently support 217 country codes. The standard way to refer to a country is by using its [ISO
+We currently support 218 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
@@ -672,6 +672,13 @@ any) in brackets, available languages and additional holiday categories. All cou
 <td></td>
 </tr>
 <tr>
+<td>Gibraltar</td>
+<td>GI</td>
+<td></td>
+<td><strong>en_GB</strong>, en_US</td>
+<td></td>
+</tr>
+<tr>
 <td>Greece</td>
 <td>GR</td>
 <td></td>
diff --git a/holidays/countries/__init__.py b/holidays/countries/__init__.py
index 8e491c56..27898188 100644
--- a/holidays/countries/__init__.py
+++ b/holidays/countries/__init__.py
@@ -92,6 +92,7 @@ from holidays.countries.gabon import Gabon, GA, GAB
 from holidays.countries.georgia import Georgia, GE, GEO
 from holidays.countries.germany import Germany, DE, DEU
 from holidays.countries.ghana import Ghana, GH, GHA
+from holidays.countries.gibraltar import Gibraltar, GI, GIB
 from holidays.countries.greece import Greece, GR, GRC
 from holidays.countries.greenland import Greenland, GL, GRL
 from holidays.countries.grenada import Grenada, GD, GRD
diff --git a/holidays/countries/gibraltar.py b/holidays/countries/gibraltar.py
new file mode 100644
index 00000000..33ea5586
--- /dev/null
+++ b/holidays/countries/gibraltar.py
@@ -0,0 +1,219 @@
+#  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 JAN, FEB, APR, MAY, JUN, AUG, 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 Gibraltar(ObservedHolidayBase, ChristianHolidays, InternationalHolidays, StaticHolidays):
+    """Gibraltar holidays.
+
+    References:
+        * <https://en.wikipedia.org/wiki/Public_holidays_in_Gibraltar>
+        * [2000](https://web.archive.org/web/20250714134510/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/1999s073.pdf)
+        * [2001](https://web.archive.org/web/20250714134609/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2000s041.pdf)
+        * [2003](https://web.archive.org/web/20250713064759/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2002s094.pdf)
+        * [2004](https://web.archive.org/web/20250713065008/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2003s105.pdf)
+        * [2005](https://web.archive.org/web/20250713071914/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2004s069.pdf)
+        * [2006](https://web.archive.org/web/20250713072021/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2005s111.pdf)
+        * [2007](https://web.archive.org/web/20250713072021/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2006s122.pdf)
+        * [2008](https://web.archive.org/web/20250713072026/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2007s113.pdf)
+        * [2009](https://web.archive.org/web/20250713072221/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2008s073.pdf)
+        * [2010](https://web.archive.org/web/20250713072222/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2009s049.pdf)
+        * [2011](https://web.archive.org/web/20250713072228/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2010s149.pdf)
+        * [2012](https://web.archive.org/web/20250713073334/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2011s189.pdf)
+        * [2013](https://web.archive.org/web/20250713162959/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2012s146.pdf)
+        * [2014](https://web.archive.org/web/20250713103345/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2013s149.pdf)
+        * [2015](https://web.archive.org/web/20250713163521/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2014s203.pdf)
+        * [2016](https://web.archive.org/web/20250713164519/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2015s196.pdf)
+        * [2017](https://web.archive.org/web/20250713073752/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2016s217.pdf)
+        * [2018](https://web.archive.org/web/20250714135250/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2017s224.pdf)
+        * [2019](https://web.archive.org/web/20250713071343/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2018s229.pdf)
+        * [2020](https://web.archive.org/web/20250714135425/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2019s217.pdf)
+        * [2021](https://web.archive.org/web/20250421063152/https://www.gibraltarlaws.gov.gi/legislations/bank-and-public-holidays-order-2020-5593/download)
+        * [2022](https://web.archive.org/web/20250414134257/https://www.gibraltarlaws.gov.gi/legislations/bank-and-public-holidays-order-2021-6286/version/21-10-2021/download)
+        * [2023](https://web.archive.org/web/20240831014104/https://www.gibraltarlaws.gov.gi/legislations/bank-and-public-holidays-order-2022-6735/version/22-02-2023/download)
+        * [2024](https://web.archive.org/web/20250502030403/https://www.gibraltarlaws.gov.gi/legislations/bank-and-public-holidays-order-2023-7215/version/06-11-2023/download)
+        * [2025](https://web.archive.org/web/20250714135600/https://www.gibraltarlaws.gov.gi/legislations/bank-and-public-holidays-order-2024-7456/download)
+    """
+
+    country = "GI"
+    default_language = "en_GB"
+    # %s (observed).
+    observed_label = tr("%s (observed)")
+    # First holiday info available from 2000.
+    start_year = 2000
+    supported_languages = ("en_GB", "en_US")
+
+    def __init__(self, *args, **kwargs):
+        ChristianHolidays.__init__(self)
+        InternationalHolidays.__init__(self)
+        StaticHolidays.__init__(self, GibraltarStaticHolidays)
+        kwargs.setdefault("observed_rule", SAT_SUN_TO_NEXT_MON)
+        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")))
+
+        name = (
+            # Winter Midterm Bank Holiday.
+            tr("Winter Midterm Bank Holiday")
+            if self._year >= 2023
+            # Commonwealth Day.
+            else tr("Commonwealth Day")
+        )
+        winter_midterm_dts = {
+            2024: (FEB, 12),
+        }
+        if dt := winter_midterm_dts.get(self._year):
+            self._add_holiday(name, dt)
+        elif self._year >= 2021:
+            self._add_holiday_3rd_mon_of_feb(name)
+        else:
+            self._add_holiday_2nd_mon_of_mar(name)
+
+        # Good Friday.
+        self._add_good_friday(tr("Good Friday"))
+
+        # Easter Monday.
+        self._add_easter_monday(tr("Easter Monday"))
+
+        if self._year >= 2013:
+            # Workers' Memorial Day.
+            name = tr("Workers' Memorial Day")
+            workers_memorial_dts = {
+                2013: (APR, 26),
+                2015: (APR, 27),
+            }
+            if dt := workers_memorial_dts.get(self._year):
+                self._add_holiday(name, dt)
+            else:
+                self._add_observed(self._add_holiday_apr_28(name))
+
+        # May Day.
+        name = tr("May Day")
+        may_day_dts = {
+            2007: (MAY, 7),
+            2008: (MAY, 5),
+            2009: (MAY, 4),
+        }
+        if dt := may_day_dts.get(self._year):
+            self._add_holiday(name, dt)
+        else:
+            self._add_observed(self._add_holiday_may_1(name))
+
+        # Spring Bank Holiday.
+        name = tr("Spring Bank Holiday")
+        spring_bank_dts = {
+            2012: (JUN, 4),
+            2022: (JUN, 2),
+        }
+        if dt := spring_bank_dts.get(self._year):
+            self._add_holiday(name, dt)
+        else:
+            self._add_holiday_last_mon_of_may(name)
+
+        name = (
+            # King's Birthday.
+            tr("King's Birthday")
+            if self._year >= 2023
+            # Queen's Birthday.
+            else tr("Queen's Birthday")
+        )
+        sovereign_birthday_dts = {
+            2000: (JUN, 19),
+            2001: (JUN, 18),
+            2006: (JUN, 19),
+            2007: (JUN, 18),
+            2012: (JUN, 18),
+            2013: (JUN, 17),
+            2017: (JUN, 19),
+            2019: (JUN, 17),
+            2023: (JUN, 19),
+            2024: (JUN, 17),
+        }
+        if dt := sovereign_birthday_dts.get(self._year):
+            self._add_holiday(name, dt)
+        else:
+            self._add_holiday_2_days_past_2nd_sat_of_jun(name)
+
+        self._add_holiday_last_mon_of_aug(
+            # Summer Bank Holiday.
+            tr("Summer Bank Holiday")
+            if 2002 <= self._year <= 2007
+            # Late Summer Bank Holiday.
+            else tr("Late Summer Bank Holiday")
+        )
+
+        # Gibraltar National Day.
+        name = tr("Gibraltar National Day")
+        national_day_dts = {
+            2016: (SEP, 5),
+            2017: (SEP, 4),
+        }
+        if dt := national_day_dts.get(self._year):
+            self._add_holiday(name, dt)
+        else:
+            self._add_observed(self._add_holiday_sep_10(name))
+
+        self._add_observed(
+            # Christmas Day.
+            self._add_christmas_day(tr("Christmas Day")),
+            rule=SAT_SUN_TO_NEXT_MON_TUE,
+        )
+
+        self._add_observed(
+            # Boxing Day.
+            self._add_christmas_day_two(tr("Boxing Day")),
+            rule=SAT_SUN_TO_NEXT_MON_TUE,
+        )
+
+
+class GI(Gibraltar):
+    pass
+
+
+class GIB(Gibraltar):
+    pass
+
+
+class GibraltarStaticHolidays(StaticHolidays):
+    """Gibraltar special holidays.
+
+    References:
+        * [Evacuation Commemoration Day, 2015](https://web.archive.org/web/20250714174537/https://www.gibraltarlaws.gov.gi/uploads/legislations/banking-and-financial-dealings/B&P%20Holidays/2015s112.pdf)
+    """
+
+    special_public_holidays = {
+        # Tercentenary Holiday.
+        2004: (AUG, 4, tr("Tercentenary Holiday")),
+        # Bank Holiday.
+        2009: (JAN, 12, tr("Bank Holiday")),
+        # Queen's Diamond Jubilee.
+        2012: (JUN, 5, tr("Queen's Diamond Jubilee")),
+        # Evacuation Commemoration Day.
+        2015: (SEP, 7, tr("Evacuation Commemoration Day")),
+        # 75th Anniversary of VE Day.
+        2020: (MAY, 8, tr("75th Anniversary of VE Day")),
+        # Queen's Platinum Jubilee.
+        2022: (JUN, 3, tr("Platinum Jubilee")),
+        # Special King’s Coronation Bank Holiday.
+        2023: (MAY, 8, tr("Special King's Coronation Bank Holiday")),
+    }
diff --git a/holidays/locale/en_GB/LC_MESSAGES/GI.po b/holidays/locale/en_GB/LC_MESSAGES/GI.po
new file mode 100644
index 00000000..1cb45508
--- /dev/null
+++ b/holidays/locale/en_GB/LC_MESSAGES/GI.po
@@ -0,0 +1,120 @@
+#  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)
+#
+# Gibraltar holidays.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Holidays 0.77\n"
+"POT-Creation-Date: 2025-07-13 15:21+0500\n"
+"PO-Revision-Date: 2025-07-13 15:21+0500\n"
+"Last-Translator: Wasif Shahzad <wasif_shahzad_1@outlook.com>\n"
+"Language-Team: Holidays Localization Team\n"
+"Language: en_GB\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_GB\n"
+
+#. %s (observed).
+#, c-format
+msgid "%s (observed)"
+msgstr ""
+
+#. New Year's Day.
+msgid "New Year's Day"
+msgstr ""
+
+#. Winter Midterm Bank Holiday.
+msgid "Winter Midterm Bank Holiday"
+msgstr ""
+
+#. Commonwealth Day.
+msgid "Commonwealth Day"
+msgstr ""
+
+#. Good Friday.
+msgid "Good Friday"
+msgstr ""
+
+#. Easter Monday.
+msgid "Easter Monday"
+msgstr ""
+
+#. Workers' Memorial Day.
+msgid "Workers' Memorial Day"
+msgstr ""
+
+#. May Day.
+msgid "May Day"
+msgstr ""
+
+#. Spring Bank Holiday.
+msgid "Spring Bank Holiday"
+msgstr ""
+
+#. King's Birthday.
+msgid "King's Birthday"
+msgstr ""
+
+#. Queen's Birthday.
+msgid "Queen's Birthday"
+msgstr ""
+
+#. Summer Bank Holiday.
+msgid "Summer Bank Holiday"
+msgstr ""
+
+#. Late Summer Bank Holiday.
+msgid "Late Summer Bank Holiday"
+msgstr ""
+
+#. Gibraltar National Day.
+msgid "Gibraltar National Day"
+msgstr ""
+
+#. Christmas Day.
+msgid "Christmas Day"
+msgstr ""
+
+#. Boxing Day.
+msgid "Boxing Day"
+msgstr ""
+
+#. Tercentenary Holiday.
+msgid "Tercentenary Holiday"
+msgstr ""
+
+#. Bank Holiday.
+msgid "Bank Holiday"
+msgstr ""
+
+#. Queen's Diamond Jubilee.
+msgid "Queen's Diamond Jubilee"
+msgstr ""
+
+#. Evacuation Commemoration Day.
+msgid "Evacuation Commemoration Day"
+msgstr ""
+
+#. 75th Anniversary of VE Day.
+msgid "75th Anniversary of VE Day"
+msgstr ""
+
+#. Queen's Platinum Jubilee.
+msgid "Platinum Jubilee"
+msgstr ""
+
+#. Special King’s Coronation Bank Holiday.
+msgid "Special King's Coronation Bank Holiday"
+msgstr ""
diff --git a/holidays/locale/en_US/LC_MESSAGES/GI.po b/holidays/locale/en_US/LC_MESSAGES/GI.po
new file mode 100644
index 00000000..bc50978f
--- /dev/null
+++ b/holidays/locale/en_US/LC_MESSAGES/GI.po
@@ -0,0 +1,121 @@
+#  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)
+#
+# Gibraltar holidays en_US localization.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Holidays 0.77\n"
+"POT-Creation-Date: 2025-07-13 15:21+0500\n"
+"PO-Revision-Date: 2025-07-13 15:23+0500\n"
+"Last-Translator: Wasif Shahzad <wasif_shahzad_1@outlook.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-Generator: Poedit 3.6\n"
+"X-Source-Language: en_GB\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"
+
+#. Winter Midterm Bank Holiday.
+msgid "Winter Midterm Bank Holiday"
+msgstr "Winter Midterm Bank Holiday"
+
+#. Commonwealth Day.
+msgid "Commonwealth Day"
+msgstr "Commonwealth Day"
+
+#. Good Friday.
+msgid "Good Friday"
+msgstr "Good Friday"
+
+#. Easter Monday.
+msgid "Easter Monday"
+msgstr "Easter Monday"
+
+#. Workers' Memorial Day.
+msgid "Workers' Memorial Day"
+msgstr "Workers' Memorial Day"
+
+#. May Day.
+msgid "May Day"
+msgstr "May Day"
+
+#. Spring Bank Holiday.
+msgid "Spring Bank Holiday"
+msgstr "Spring Bank Holiday"
+
+#. King's Birthday.
+msgid "King's Birthday"
+msgstr "King's Birthday"
+
+#. Queen's Birthday.
+msgid "Queen's Birthday"
+msgstr "Queen's Birthday"
+
+#. Summer Bank Holiday.
+msgid "Summer Bank Holiday"
+msgstr "Summer Bank Holiday"
+
+#. Late Summer Bank Holiday.
+msgid "Late Summer Bank Holiday"
+msgstr "Late Summer Bank Holiday"
+
+#. Gibraltar National Day.
+msgid "Gibraltar National Day"
+msgstr "Gibraltar National Day"
+
+#. Christmas Day.
+msgid "Christmas Day"
+msgstr "Christmas Day"
+
+#. Boxing Day.
+msgid "Boxing Day"
+msgstr "Boxing Day"
+
+#. Tercentenary Holiday.
+msgid "Tercentenary Holiday"
+msgstr "Tercentenary Holiday"
+
+#. Bank Holiday.
+msgid "Bank Holiday"
+msgstr "Bank Holiday"
+
+#. Queen's Diamond Jubilee.
+msgid "Queen's Diamond Jubilee"
+msgstr "Queen's Diamond Jubilee"
+
+#. Evacuation Commemoration Day.
+msgid "Evacuation Commemoration Day"
+msgstr "Evacuation Commemoration Day"
+
+#. 75th Anniversary of VE Day.
+msgid "75th Anniversary of VE Day"
+msgstr "75th Anniversary of VE Day"
+
+#. Queen's Platinum Jubilee.
+msgid "Platinum Jubilee"
+msgstr "Queen's Platinum Jubilee"
+
+#. Special King’s Coronation Bank Holiday.
+msgid "Special King's Coronation Bank Holiday"
+msgstr "Special King's Coronation Bank Holiday"
diff --git a/holidays/registry.py b/holidays/registry.py
index 18196608..176c5988 100644
--- a/holidays/registry.py
+++ b/holidays/registry.py
@@ -96,6 +96,7 @@ COUNTRIES: RegistryDict = {
     "georgia": ("Georgia", "GE", "GEO"),
     "germany": ("Germany", "DE", "DEU"),
     "ghana": ("Ghana", "GH", "GHA"),
+    "gibraltar": ("Gibraltar", "GI", "GIB"),
     "greece": ("Greece", "GR", "GRC"),
     "greenland": ("Greenland", "GL", "GRL"),
     "grenada": ("Grenada", "GD", "GRD"),
diff --git a/requirements/dev.txt b/requirements/dev.txt
index 9f5f076e..99d43f8e 100644
--- a/requirements/dev.txt
+++ b/requirements/dev.txt
@@ -8,7 +8,7 @@ lingva==5.0.6
 pre-commit==4.2.0
 pygithub==2.6.1
 requests==2.32.4
-ruff==0.12.2
+ruff==0.12.3
 tox==4.27.0
 urllib3>=2.2.2 # not directly required, pinned by Snyk to avoid a vulnerability
 zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability


Test patch:
diff --git a/tests/countries/test_gibraltar.py b/tests/countries/test_gibraltar.py
new file mode 100644
index 00000000..87be1117
--- /dev/null
+++ b/tests/countries/test_gibraltar.py
@@ -0,0 +1,284 @@
+#  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.gibraltar import Gibraltar, GI, GIB
+from tests.common import CommonCountryTests
+
+
+class TestGibraltar(CommonCountryTests, TestCase):
+    @classmethod
+    def setUpClass(cls):
+        years = range(2000, 2050)
+        super().setUpClass(Gibraltar, years=years, years_non_observed=years)
+
+    def test_country_aliases(self):
+        self.assertAliases(Gibraltar, GI, GIB)
+
+    def test_no_holidays(self):
+        self.assertNoHolidays(Gibraltar(years=1999))
+
+    def test_special_holidays(self):
+        for dt, name in (
+            ("2004-08-04", "Tercentenary Holiday"),
+            ("2012-06-05", "Queen's Diamond Jubilee"),
+            ("2020-05-08", "75th Anniversary of VE Day"),
+            ("2022-06-03", "Platinum Jubilee"),
+            ("2009-01-12", "Bank Holiday"),
+            ("2015-09-07", "Evacuation Commemoration Day"),
+            ("2023-05-08", "Special King's Coronation Bank Holiday"),
+        ):
+            self.assertHolidayName(name, dt)
+
+    def test_new_years_day(self):
+        name = "New Year's Day"
+        self.assertHolidayName(name, (f"{year}-01-01" for year in range(2000, 2050)))
+        obs_dt = (
+            "2012-01-02",
+            "2017-01-02",
+            "2022-01-03",
+            "2023-01-02",
+        )
+        self.assertHolidayName(f"{name} (observed)", obs_dt)
+        self.assertNoNonObservedHoliday(obs_dt)
+
+    def test_winter_bank_holiday(self):
+        name = "Winter Midterm Bank Holiday"
+        self.assertHolidayName(
+            name,
+            "2023-02-20",
+            "2024-02-12",
+            "2025-02-17",
+        )
+        self.assertHolidayName(name, range(2023, 2050))
+        self.assertNoHolidayName(name, range(2000, 2023))
+
+    def test_commonwealth_day(self):
+        name = "Commonwealth Day"
+        self.assertHolidayName(
+            name,
+            "2018-03-12",
+            "2019-03-11",
+            "2020-03-09",
+            "2021-02-15",
+            "2022-02-21",
+        )
+        self.assertHolidayName(name, range(2000, 2023))
+        self.assertNoHolidayName(name, range(2023, 2050))
+
+    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(2000, 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(2000, 2050))
+
+    def test_workers_memorial_day(self):
+        name = "Workers' Memorial Day"
+        self.assertHolidayName(
+            name,
+            "2020-04-28",
+            "2021-04-28",
+            "2022-04-28",
+            "2023-04-28",
+            "2024-04-28",
+            "2025-04-28",
+        )
+        self.assertHolidayName(name, range(2013, 2050))
+        self.assertNoHolidayName(name, range(2000, 2013))
+        obs_dt = (
+            "2018-04-30",
+            "2019-04-29",
+            "2024-04-29",
+        )
+        self.assertHolidayName(f"{name} (observed)", obs_dt)
+        self.assertNoNonObservedHoliday(obs_dt)
+
+    def test_may_day(self):
+        name = "May Day"
+        self.assertHolidayName(
+            name, (f"{year}-05-01" for year in (*range(2000, 2007), *range(2010, 2050)))
+        )
+        self.assertHolidayName(
+            name,
+            "2007-05-07",
+            "2008-05-05",
+            "2009-05-04",
+        )
+        obs_dt = (
+            "2011-05-02",
+            "2016-05-02",
+            "2021-05-03",
+            "2022-05-02",
+        )
+        self.assertHolidayName(f"{name} (observed)", obs_dt)
+        self.assertNoNonObservedHoliday(obs_dt)
+
+    def test_spring_bank_holiday(self):
+        name = "Spring Bank Holiday"
+        self.assertHolidayName(
+            name,
+            "2020-05-25",
+            "2021-05-31",
+            "2022-06-02",
+            "2023-05-29",
+            "2024-05-27",
+            "2025-05-26",
+        )
+        self.assertHolidayName(name, range(2000, 2050))
+
+    def test_queens_birthday(self):
+        name = "Queen's Birthday"
+        self.assertHolidayName(
+            name,
+            "2018-06-11",
+            "2019-06-17",
+            "2020-06-15",
+            "2021-06-14",
+            "2022-06-13",
+        )
+        self.assertHolidayName(name, range(2000, 2023))
+        self.assertNoHolidayName(name, range(2023, 2050))
+
+    def test_kings_birthday(self):
+        name = "King's Birthday"
+        self.assertHolidayName(
+            name,
+            "2023-06-19",
+            "2024-06-17",
+            "2025-06-16",
+        )
+        self.assertHolidayName(name, range(2023, 2050))
+        self.assertNoHolidayName(name, range(2000, 2023))
+
+    def test_summer_bank_holiday(self):
+        first_name = "Summer Bank Holiday"
+        self.assertHolidayName(
+            first_name,
+            "2002-08-26",
+            "2003-08-25",
+            "2004-08-30",
+            "2005-08-29",
+            "2006-08-28",
+            "2007-08-27",
+        )
+        self.assertNoHolidayName(first_name, range(2000, 2002), range(2008, 2050))
+
+        second_name = "Late Summer Bank Holiday"
+        self.assertHolidayName(
+            second_name,
+            "2020-08-31",
+            "2021-08-30",
+            "2022-08-29",
+            "2023-08-28",
+            "2024-08-26",
+            "2025-08-25",
+        )
+        self.assertHolidayName(second_name, range(2000, 2002), range(2008, 2050))
+        self.assertNoHolidayName(second_name, range(2002, 2008))
+
+    def test_national_day(self):
+        name = "Gibraltar National Day"
+        self.assertHolidayName(
+            name, (f"{year}-09-10" for year in (*range(2000, 2016), *range(2018, 2050)))
+        )
+        self.assertHolidayName(
+            name,
+            "2016-09-05",
+            "2017-09-04",
+        )
+        obs_dt = (
+            "2011-09-12",
+            "2022-09-12",
+            "2023-09-11",
+        )
+        self.assertHolidayName(f"{name} (observed)", obs_dt)
+        self.assertNoNonObservedHoliday(obs_dt)
+
+    def test_christmas_day(self):
+        name = "Christmas Day"
+        self.assertHolidayName(name, (f"{year}-12-25" for year in range(2000, 2050)))
+        obs_dt = (
+            "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(2000, 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(
+            ("2024-01-01", "New Year's Day"),
+            ("2024-02-12", "Winter Midterm Bank Holiday"),
+            ("2024-03-29", "Good Friday"),
+            ("2024-04-01", "Easter Monday"),
+            ("2024-04-28", "Workers' Memorial Day"),
+            ("2024-04-29", "Workers' Memorial Day (observed)"),
+            ("2024-05-01", "May Day"),
+            ("2024-05-27", "Spring Bank Holiday"),
+            ("2024-06-17", "King's Birthday"),
+            ("2024-08-26", "Late Summer Bank Holiday"),
+            ("2024-09-10", "Gibraltar National Day"),
+            ("2024-12-25", "Christmas Day"),
+            ("2024-12-26", "Boxing Day"),
+        )
+
+    def test_l10n_en_us(self):
+        self.assertLocalizedHolidays(
+            "en_US",
+            ("2024-01-01", "New Year's Day"),
+            ("2024-02-12", "Winter Midterm Bank Holiday"),
+            ("2024-03-29", "Good Friday"),
+            ("2024-04-01", "Easter Monday"),
+            ("2024-04-28", "Workers' Memorial Day"),
+            ("2024-04-29", "Workers' Memorial Day (observed)"),
+            ("2024-05-01", "May Day"),
+            ("2024-05-27", "Spring Bank Holiday"),
+            ("2024-06-17", "King's Birthday"),
+            ("2024-08-26", "Late Summer Bank Holiday"),
+            ("2024-09-10", "Gibraltar National Day"),
+            ("2024-12-25", "Christmas Day"),
+            ("2024-12-26", "Boxing Day"),
+        )