From 949dcc89600e82c632d62ee595c1b842a35fbdc4 Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Mon, 29 Jun 2026 22:13:30 +0530 Subject: [PATCH 1/7] Add London Stock Exchange (XLON) financial market Add the London Stock Exchange, one of the world's largest exchanges, to the supported financial markets. The LSE is closed on weekends and on the bank holidays observed in England and Wales, plus a small number of one-off royal bank holidays (jubilees, the 2011 royal wedding, the 2022 state funeral, and the 2023 coronation). Includes XLON/LSE aliases, full test coverage, registry and README entries. Output matches the library's existing England and Wales bank holiday data for 2000-2030. Add Eesh Saxena to CONTRIBUTORS. --- CONTRIBUTORS | 1 + README.md | 7 + holidays/financial/__init__.py | 1 + holidays/financial/london_stock_exchange.py | 112 ++++++++++++++ holidays/registry.py | 1 + tests/financial/test_london_stock_exchange.py | 145 ++++++++++++++++++ 6 files changed, 267 insertions(+) create mode 100644 holidays/financial/london_stock_exchange.py create mode 100644 tests/financial/test_london_stock_exchange.py diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 83e3b119d9..b5feae9cbc 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -54,6 +54,7 @@ Douglas Franklin Eden Juscelino Edison Robles Edward Betts +Eesh Saxena Eldar Mustafayev Emmanuel Arias Eugenio Panadero Maciá diff --git a/README.md b/README.md index 1c1f02821b..b068aaa7d9 100644 --- a/README.md +++ b/README.md @@ -1994,6 +1994,13 @@ code when available. The following financial markets are available: +London Stock Exchange +XLON +London Stock Exchange (LSE) market holidays + + + + NASDAQ XNAS National Association of Securities Dealers Automated Quotations (NASDAQ) holidays diff --git a/holidays/financial/__init__.py b/holidays/financial/__init__.py index 2ddaab7c7f..dc4db09f40 100644 --- a/holidays/financial/__init__.py +++ b/holidays/financial/__init__.py @@ -18,6 +18,7 @@ from holidays.financial.hong_kong_stock_exchange import HongKongStockExchange, XHKG, HKEX, SEHK from holidays.financial.ice_futures_europe import IceFuturesEurope, ICEFuturesEurope, IFEU from holidays.financial.japan_exchange import JapanExchange, XJPX, JPX, TSE, OSE +from holidays.financial.london_stock_exchange import LondonStockExchange, XLON, LSE from holidays.financial.nasdaq import NASDAQ, XNAS from holidays.financial.national_stock_exchange_of_india import ( NationalStockExchangeOfIndia, diff --git a/holidays/financial/london_stock_exchange.py b/holidays/financial/london_stock_exchange.py new file mode 100644 index 0000000000..7f3357c2d1 --- /dev/null +++ b/holidays/financial/london_stock_exchange.py @@ -0,0 +1,112 @@ +# 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 (c) 2017-2023 +# ryanss (c) 2014-2017 +# Website: https://github.com/vacanza/holidays +# License: MIT (see LICENSE file) + +from holidays.calendars.gregorian import APR, MAY, JUN, 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 LondonStockExchange( + ObservedHolidayBase, ChristianHolidays, InternationalHolidays, StaticHolidays +): + """London Stock Exchange holidays. + + The London Stock Exchange (LSE) is closed on weekends and on the bank + holidays observed in England and Wales, together with a small number of + one-off bank holidays (royal events). + + References: + * + * + * [LSE business days](https://www.londonstockexchange.com/equities-trading/business-days) + """ + + market = "XLON" + observed_label = "%s (observed)" + start_year = 2000 + + def __init__(self, *args, **kwargs): + ChristianHolidays.__init__(self) + InternationalHolidays.__init__(self) + StaticHolidays.__init__(self, LondonStockExchangeStaticHolidays) + 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("New Year's Day")) + + # Good Friday. + self._add_good_friday("Good Friday") + + # Easter Monday. + self._add_easter_monday("Easter Monday") + + # May Day. + if self._year == 2020: + # Moved to mark the 75th anniversary of VE Day. + self._add_holiday_may_8("May Day") + else: + self._add_holiday_1st_mon_of_may("May Day") + + # Spring Bank Holiday. + # Moved on the years of a Jubilee bank holiday. + spring_bank_dates = { + 2002: (JUN, 4), + 2012: (JUN, 4), + 2022: (JUN, 2), + } + name = "Spring Bank Holiday" + if dt := spring_bank_dates.get(self._year): + self._add_holiday(name, dt) + else: + self._add_holiday_last_mon_of_may(name) + + # Late Summer Bank Holiday. + self._add_holiday_last_mon_of_aug("Late Summer Bank Holiday") + + # 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 XLON(LondonStockExchange): + pass + + +class LSE(LondonStockExchange): + pass + + +class LondonStockExchangeStaticHolidays: + """Special one-off bank holidays observed by the London Stock Exchange. + + References: + * + """ + + special_public_holidays = { + 2002: (JUN, 3, "Golden Jubilee of Elizabeth II"), + 2011: (APR, 29, "Wedding of William and Catherine"), + 2012: (JUN, 5, "Diamond Jubilee of Elizabeth II"), + 2022: ( + (JUN, 3, "Platinum Jubilee of Elizabeth II"), + (SEP, 19, "State Funeral of Queen Elizabeth II"), + ), + 2023: (MAY, 8, "Coronation of Charles III"), + } diff --git a/holidays/registry.py b/holidays/registry.py index 9359fa25c1..e99f085d60 100644 --- a/holidays/registry.py +++ b/holidays/registry.py @@ -294,6 +294,7 @@ "hong_kong_stock_exchange": ("HongKongStockExchange", "XHKG", "HKEX", "SEHK"), "ice_futures_europe": ("IceFuturesEurope", "IFEU", "ICEFuturesEurope"), "japan_exchange": ("JapanExchange", "XJPX", "JPX", "TSE", "OSE"), + "london_stock_exchange": ("LondonStockExchange", "XLON", "LSE"), "nasdaq": ("NASDAQ", "XNAS"), "national_stock_exchange_of_india": ("NationalStockExchangeOfIndia", "XNSE", "NSE"), "ny_stock_exchange": ("NewYorkStockExchange", "XNYS", "NYSE"), diff --git a/tests/financial/test_london_stock_exchange.py b/tests/financial/test_london_stock_exchange.py new file mode 100644 index 0000000000..3b7269e9c5 --- /dev/null +++ b/tests/financial/test_london_stock_exchange.py @@ -0,0 +1,145 @@ +# 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 (c) 2017-2023 +# ryanss (c) 2014-2017 +# Website: https://github.com/vacanza/holidays +# License: MIT (see LICENSE file) + +from unittest import TestCase + +from holidays.financial.london_stock_exchange import LondonStockExchange, XLON, LSE +from tests.common import CommonFinancialTests + + +class TestLondonStockExchange(CommonFinancialTests, TestCase): + @classmethod + def setUpClass(cls): + super().setUpClass(LondonStockExchange) + + def test_market_aliases(self): + self.assertAliases(LondonStockExchange, XLON, LSE) + + def test_no_holidays(self): + self.assertNoHolidays(LondonStockExchange(years=1999)) + + def test_2002(self): + self.assertHolidays( + LondonStockExchange(years=2002), + ("2002-01-01", "New Year's Day"), + ("2002-03-29", "Good Friday"), + ("2002-04-01", "Easter Monday"), + ("2002-05-06", "May Day"), + ("2002-06-03", "Golden Jubilee of Elizabeth II"), + ("2002-06-04", "Spring Bank Holiday"), + ("2002-08-26", "Late Summer Bank Holiday"), + ("2002-12-25", "Christmas Day"), + ("2002-12-26", "Boxing Day"), + ) + + def test_2011(self): + self.assertHolidays( + LondonStockExchange(years=2011), + ("2011-01-01", "New Year's Day"), + ("2011-01-03", "New Year's Day (observed)"), + ("2011-04-22", "Good Friday"), + ("2011-04-25", "Easter Monday"), + ("2011-04-29", "Wedding of William and Catherine"), + ("2011-05-02", "May Day"), + ("2011-05-30", "Spring Bank Holiday"), + ("2011-08-29", "Late Summer Bank Holiday"), + ("2011-12-25", "Christmas Day"), + ("2011-12-26", "Boxing Day"), + ("2011-12-27", "Christmas Day (observed)"), + ) + + def test_2020(self): + self.assertHolidays( + LondonStockExchange(years=2020), + ("2020-01-01", "New Year's Day"), + ("2020-04-10", "Good Friday"), + ("2020-04-13", "Easter Monday"), + ("2020-05-08", "May Day"), + ("2020-05-25", "Spring Bank Holiday"), + ("2020-08-31", "Late Summer Bank Holiday"), + ("2020-12-25", "Christmas Day"), + ("2020-12-26", "Boxing Day"), + ("2020-12-28", "Boxing Day (observed)"), + ) + + def test_2021(self): + self.assertHolidays( + LondonStockExchange(years=2021), + ("2021-01-01", "New Year's Day"), + ("2021-04-02", "Good Friday"), + ("2021-04-05", "Easter Monday"), + ("2021-05-03", "May Day"), + ("2021-05-31", "Spring Bank Holiday"), + ("2021-08-30", "Late Summer Bank Holiday"), + ("2021-12-25", "Christmas Day"), + ("2021-12-26", "Boxing Day"), + ("2021-12-27", "Christmas Day (observed)"), + ("2021-12-28", "Boxing Day (observed)"), + ) + + def test_2022(self): + self.assertHolidays( + LondonStockExchange(years=2022), + ("2022-01-01", "New Year's Day"), + ("2022-01-03", "New Year's Day (observed)"), + ("2022-04-15", "Good Friday"), + ("2022-04-18", "Easter Monday"), + ("2022-05-02", "May Day"), + ("2022-06-02", "Spring Bank Holiday"), + ("2022-06-03", "Platinum Jubilee of Elizabeth II"), + ("2022-08-29", "Late Summer Bank Holiday"), + ("2022-09-19", "State Funeral of Queen Elizabeth II"), + ("2022-12-25", "Christmas Day"), + ("2022-12-26", "Boxing Day"), + ("2022-12-27", "Christmas Day (observed)"), + ) + + def test_2023(self): + self.assertHolidays( + LondonStockExchange(years=2023), + ("2023-01-01", "New Year's Day"), + ("2023-01-02", "New Year's Day (observed)"), + ("2023-04-07", "Good Friday"), + ("2023-04-10", "Easter Monday"), + ("2023-05-01", "May Day"), + ("2023-05-08", "Coronation of Charles III"), + ("2023-05-29", "Spring Bank Holiday"), + ("2023-08-28", "Late Summer Bank Holiday"), + ("2023-12-25", "Christmas Day"), + ("2023-12-26", "Boxing Day"), + ) + + def test_2024(self): + self.assertHolidays( + LondonStockExchange(years=2024), + ("2024-01-01", "New Year's Day"), + ("2024-03-29", "Good Friday"), + ("2024-04-01", "Easter Monday"), + ("2024-05-06", "May Day"), + ("2024-05-27", "Spring Bank Holiday"), + ("2024-08-26", "Late Summer Bank Holiday"), + ("2024-12-25", "Christmas Day"), + ("2024-12-26", "Boxing Day"), + ) + + def test_2025(self): + self.assertHolidays( + LondonStockExchange(years=2025), + ("2025-01-01", "New Year's Day"), + ("2025-04-18", "Good Friday"), + ("2025-04-21", "Easter Monday"), + ("2025-05-05", "May Day"), + ("2025-05-26", "Spring Bank Holiday"), + ("2025-08-25", "Late Summer Bank Holiday"), + ("2025-12-25", "Christmas Day"), + ("2025-12-26", "Boxing Day"), + ) From 613b182d1fb787748760f4a0ae220a50c23766f1 Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Sat, 4 Jul 2026 08:29:40 +0530 Subject: [PATCH 2/7] Add LSE half-day trading sessions (Christmas Eve, New Year's Eve) The London Stock Exchange runs a shortened session with an early close on Christmas Eve and New Year's Eve. These are now exposed under the HALF_DAY category, following the existing exchange half-day pattern. --- holidays/financial/london_stock_exchange.py | 12 ++++++++++++ tests/financial/test_london_stock_exchange.py | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/holidays/financial/london_stock_exchange.py b/holidays/financial/london_stock_exchange.py index 7f3357c2d1..858a6f3796 100644 --- a/holidays/financial/london_stock_exchange.py +++ b/holidays/financial/london_stock_exchange.py @@ -11,6 +11,7 @@ # License: MIT (see LICENSE file) from holidays.calendars.gregorian import APR, MAY, JUN, SEP +from holidays.constants import HALF_DAY, PUBLIC from holidays.groups import ChristianHolidays, InternationalHolidays, StaticHolidays from holidays.observed_holiday_base import ( ObservedHolidayBase, @@ -28,6 +29,9 @@ class LondonStockExchange( holidays observed in England and Wales, together with a small number of one-off bank holidays (royal events). + On Christmas Eve and New Year's Eve the exchange runs a shortened trading + session (an early close), available under the ``HALF_DAY`` category. + References: * * @@ -37,6 +41,7 @@ class LondonStockExchange( market = "XLON" observed_label = "%s (observed)" start_year = 2000 + supported_categories = (HALF_DAY, PUBLIC) def __init__(self, *args, **kwargs): ChristianHolidays.__init__(self) @@ -84,6 +89,13 @@ def _populate_public_holidays(self): # Boxing Day. self._add_observed(self._add_christmas_day_two("Boxing Day"), rule=SAT_SUN_TO_NEXT_MON_TUE) + def _populate_half_day_holidays(self): + # Christmas Eve. + self._add_christmas_eve("Christmas Eve") + + # New Year's Eve. + self._add_new_years_eve("New Year's Eve") + class XLON(LondonStockExchange): pass diff --git a/tests/financial/test_london_stock_exchange.py b/tests/financial/test_london_stock_exchange.py index 3b7269e9c5..8296752120 100644 --- a/tests/financial/test_london_stock_exchange.py +++ b/tests/financial/test_london_stock_exchange.py @@ -143,3 +143,10 @@ def test_2025(self): ("2025-12-25", "Christmas Day"), ("2025-12-26", "Boxing Day"), ) + + def test_2024_half_day(self): + self.assertHalfDayHolidaysInYear( + 2024, + ("2024-12-24", "Christmas Eve"), + ("2024-12-31", "New Year's Eve"), + ) From b0d20a82c4b8fd2001cb3b3fb9fabfd8f491b263 Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Sat, 4 Jul 2026 21:22:03 +0530 Subject: [PATCH 3/7] Label LSE half-day sessions as early closes --- holidays/financial/london_stock_exchange.py | 9 +++++++-- tests/financial/test_london_stock_exchange.py | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/holidays/financial/london_stock_exchange.py b/holidays/financial/london_stock_exchange.py index 858a6f3796..3a534bff2d 100644 --- a/holidays/financial/london_stock_exchange.py +++ b/holidays/financial/london_stock_exchange.py @@ -90,11 +90,16 @@ def _populate_public_holidays(self): self._add_observed(self._add_christmas_day_two("Boxing Day"), rule=SAT_SUN_TO_NEXT_MON_TUE) def _populate_half_day_holidays(self): + # On these days the exchange runs a shortened session and closes early + # (12:30). The label makes it clear to end users that trading is only + # partial rather than the day being a full market holiday. + early_close_label = "%s (early close)" + # Christmas Eve. - self._add_christmas_eve("Christmas Eve") + self._add_christmas_eve(self._format_holiday_name(early_close_label, "Christmas Eve")) # New Year's Eve. - self._add_new_years_eve("New Year's Eve") + self._add_new_years_eve(self._format_holiday_name(early_close_label, "New Year's Eve")) class XLON(LondonStockExchange): diff --git a/tests/financial/test_london_stock_exchange.py b/tests/financial/test_london_stock_exchange.py index 8296752120..8c7ce50764 100644 --- a/tests/financial/test_london_stock_exchange.py +++ b/tests/financial/test_london_stock_exchange.py @@ -147,6 +147,6 @@ def test_2025(self): def test_2024_half_day(self): self.assertHalfDayHolidaysInYear( 2024, - ("2024-12-24", "Christmas Eve"), - ("2024-12-31", "New Year's Eve"), + ("2024-12-24", "Christmas Eve (early close)"), + ("2024-12-31", "New Year's Eve (early close)"), ) From 57ea02b79325d638ee159e2e27136c8653f3a3b8 Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Sun, 5 Jul 2026 09:51:59 +0530 Subject: [PATCH 4/7] Refactor LSE to inherit England holidays from UnitedKingdom Reworks the London Stock Exchange to derive from UnitedKingdom via ChildEntity with parent_entity_subdivision_code="ENG" (following the JPX/SSE pattern), instead of duplicating the England bank-holiday logic. Its public holidays are now an exact alias of UnitedKingdom(subdiv="ENG"), including the one-off royal bank holidays, with no duplicated code. To keep the HALF_DAY category clean, gate UnitedKingdom's shared subdivision public holidays on `PUBLIC in self.categories`, so requesting only HALF_DAY no longer pulls in New Year's Day / Christmas / Boxing Day. Adds localization (en_GB source, en_US, th) for the half-day session strings and lists XLON's languages and HALF_DAY category in the README. --- README.md | 4 +- holidays/countries/united_kingdom.py | 3 +- holidays/financial/london_stock_exchange.py | 111 ++++-------------- holidays/locale/en_GB/LC_MESSAGES/XLON.po | 41 +++++++ holidays/locale/en_US/LC_MESSAGES/XLON.po | 41 +++++++ holidays/locale/th/LC_MESSAGES/XLON.po | 41 +++++++ tests/financial/test_london_stock_exchange.py | 10 +- 7 files changed, 159 insertions(+), 92 deletions(-) create mode 100644 holidays/locale/en_GB/LC_MESSAGES/XLON.po create mode 100644 holidays/locale/en_US/LC_MESSAGES/XLON.po create mode 100644 holidays/locale/th/LC_MESSAGES/XLON.po diff --git a/README.md b/README.md index b068aaa7d9..314f1b6ffc 100644 --- a/README.md +++ b/README.md @@ -1997,8 +1997,8 @@ code when available. The following financial markets are available: London Stock Exchange XLON London Stock Exchange (LSE) market holidays - - +en_GB, en_US, th +HALF_DAY NASDAQ diff --git a/holidays/countries/united_kingdom.py b/holidays/countries/united_kingdom.py index 3f9fc29492..340dd9f0a0 100644 --- a/holidays/countries/united_kingdom.py +++ b/holidays/countries/united_kingdom.py @@ -13,6 +13,7 @@ from gettext import gettext as tr from holidays.calendars.gregorian import APR, MAY, JUN, JUL, SEP, DEC +from holidays.constants import PUBLIC from holidays.groups import ChristianHolidays, InternationalHolidays, StaticHolidays from holidays.observed_holiday_base import ( ObservedHolidayBase, @@ -104,7 +105,7 @@ def _populate_common(self): self._add_whit_monday(tr("Whit Monday")) def _populate_subdiv_holidays(self): - if self.subdiv != "SCT": + if PUBLIC in self.categories and self.subdiv != "SCT": if self._year >= 1975: # New Year's Day. self._add_observed(self._add_new_years_day(tr("New Year's Day"))) diff --git a/holidays/financial/london_stock_exchange.py b/holidays/financial/london_stock_exchange.py index 3a534bff2d..8c8be52282 100644 --- a/holidays/financial/london_stock_exchange.py +++ b/holidays/financial/london_stock_exchange.py @@ -10,27 +10,23 @@ # Website: https://github.com/vacanza/holidays # License: MIT (see LICENSE file) -from holidays.calendars.gregorian import APR, MAY, JUN, SEP +from gettext import gettext as tr + from holidays.constants import HALF_DAY, PUBLIC -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, -) +from holidays.countries.united_kingdom import UnitedKingdom +from holidays.mixins.child_entity import ChildEntity -class LondonStockExchange( - ObservedHolidayBase, ChristianHolidays, InternationalHolidays, StaticHolidays -): +class LondonStockExchange(ChildEntity, UnitedKingdom): """London Stock Exchange holidays. - The London Stock Exchange (LSE) is closed on weekends and on the bank - holidays observed in England and Wales, together with a small number of - one-off bank holidays (royal events). + The London Stock Exchange (LSE) is closed on the bank holidays observed in + England and Wales, so its public holidays are an alias of the England + (``ENG``) subdivision of the United Kingdom, including the one-off royal + bank holidays. On Christmas Eve and New Year's Eve the exchange runs a shortened trading - session (an early close), available under the ``HALF_DAY`` category. + session (a half-day closing), available under the ``HALF_DAY`` category. References: * @@ -38,68 +34,28 @@ class LondonStockExchange( * [LSE business days](https://www.londonstockexchange.com/equities-trading/business-days) """ + country = None # type: ignore[assignment] market = "XLON" - observed_label = "%s (observed)" - start_year = 2000 + parent_entity = UnitedKingdom + parent_entity_subdivision_code = "ENG" supported_categories = (HALF_DAY, PUBLIC) - - def __init__(self, *args, **kwargs): - ChristianHolidays.__init__(self) - InternationalHolidays.__init__(self) - StaticHolidays.__init__(self, LondonStockExchangeStaticHolidays) - 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("New Year's Day")) - - # Good Friday. - self._add_good_friday("Good Friday") - - # Easter Monday. - self._add_easter_monday("Easter Monday") - - # May Day. - if self._year == 2020: - # Moved to mark the 75th anniversary of VE Day. - self._add_holiday_may_8("May Day") - else: - self._add_holiday_1st_mon_of_may("May Day") - - # Spring Bank Holiday. - # Moved on the years of a Jubilee bank holiday. - spring_bank_dates = { - 2002: (JUN, 4), - 2012: (JUN, 4), - 2022: (JUN, 2), - } - name = "Spring Bank Holiday" - if dt := spring_bank_dates.get(self._year): - self._add_holiday(name, dt) - else: - self._add_holiday_last_mon_of_may(name) - - # Late Summer Bank Holiday. - self._add_holiday_last_mon_of_aug("Late Summer Bank Holiday") - - # 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) + start_year = 2000 def _populate_half_day_holidays(self): - # On these days the exchange runs a shortened session and closes early - # (12:30). The label makes it clear to end users that trading is only - # partial rather than the day being a full market holiday. - early_close_label = "%s (early close)" + # On these days the exchange runs a shortened session (a 12:30 close), + # exposed here under the HALF_DAY category with a label so end users can + # tell it apart from a full market holiday. + + # %s (half-day closing). + half_day_closing_label = tr("%s (half-day closing)") # Christmas Eve. - self._add_christmas_eve(self._format_holiday_name(early_close_label, "Christmas Eve")) + christmas_eve = self._format_holiday_name(half_day_closing_label, tr("Christmas Eve")) + self._add_christmas_eve(christmas_eve) # New Year's Eve. - self._add_new_years_eve(self._format_holiday_name(early_close_label, "New Year's Eve")) + new_years_eve = self._format_holiday_name(half_day_closing_label, tr("New Year's Eve")) + self._add_new_years_eve(new_years_eve) class XLON(LondonStockExchange): @@ -108,22 +64,3 @@ class XLON(LondonStockExchange): class LSE(LondonStockExchange): pass - - -class LondonStockExchangeStaticHolidays: - """Special one-off bank holidays observed by the London Stock Exchange. - - References: - * - """ - - special_public_holidays = { - 2002: (JUN, 3, "Golden Jubilee of Elizabeth II"), - 2011: (APR, 29, "Wedding of William and Catherine"), - 2012: (JUN, 5, "Diamond Jubilee of Elizabeth II"), - 2022: ( - (JUN, 3, "Platinum Jubilee of Elizabeth II"), - (SEP, 19, "State Funeral of Queen Elizabeth II"), - ), - 2023: (MAY, 8, "Coronation of Charles III"), - } diff --git a/holidays/locale/en_GB/LC_MESSAGES/XLON.po b/holidays/locale/en_GB/LC_MESSAGES/XLON.po new file mode 100644 index 0000000000..90f7986ef8 --- /dev/null +++ b/holidays/locale/en_GB/LC_MESSAGES/XLON.po @@ -0,0 +1,41 @@ +# 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 (c) 2017-2023 +# ryanss (c) 2014-2017 +# Website: https://github.com/vacanza/holidays +# License: MIT (see LICENSE file) +# +# London Stock Exchange holidays. +# +msgid "" +msgstr "" +"Project-Id-Version: Holidays 0.100\n" +"Report-Msgid-Bugs-To: l10n@vacanza.dev\n" +"POT-Creation-Date: 2026-07-05 09:48+0530\n" +"PO-Revision-Date: 2026-07-05 09:48+0530\n" +"Last-Translator: eeshsaxena \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 (half-day closing). +#, c-format +msgid "%s (half-day closing)" +msgstr "" + +#. Christmas Eve. +msgid "Christmas Eve" +msgstr "" + +#. New Year's Eve. +msgid "New Year's Eve" +msgstr "" diff --git a/holidays/locale/en_US/LC_MESSAGES/XLON.po b/holidays/locale/en_US/LC_MESSAGES/XLON.po new file mode 100644 index 0000000000..e351f71b38 --- /dev/null +++ b/holidays/locale/en_US/LC_MESSAGES/XLON.po @@ -0,0 +1,41 @@ +# 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 (c) 2017-2023 +# ryanss (c) 2014-2017 +# Website: https://github.com/vacanza/holidays +# License: MIT (see LICENSE file) +# +# London Stock Exchange holidays en_US localization. +# +msgid "" +msgstr "" +"Project-Id-Version: Holidays 0.100\n" +"Report-Msgid-Bugs-To: l10n@vacanza.dev\n" +"POT-Creation-Date: 2026-07-05 09:48+0530\n" +"PO-Revision-Date: 2026-07-05 09:48+0530\n" +"Last-Translator: eeshsaxena \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_GB\n" + +#. %s (half-day closing). +#, c-format +msgid "%s (half-day closing)" +msgstr "%s (half-day closing)" + +#. Christmas Eve. +msgid "Christmas Eve" +msgstr "Christmas Eve" + +#. New Year's Eve. +msgid "New Year's Eve" +msgstr "New Year's Eve" diff --git a/holidays/locale/th/LC_MESSAGES/XLON.po b/holidays/locale/th/LC_MESSAGES/XLON.po new file mode 100644 index 0000000000..28c121d63f --- /dev/null +++ b/holidays/locale/th/LC_MESSAGES/XLON.po @@ -0,0 +1,41 @@ +# 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 (c) 2017-2023 +# ryanss (c) 2014-2017 +# Website: https://github.com/vacanza/holidays +# License: MIT (see LICENSE file) +# +# London Stock Exchange holidays th localization. +# +msgid "" +msgstr "" +"Project-Id-Version: Holidays 0.100\n" +"Report-Msgid-Bugs-To: l10n@vacanza.dev\n" +"POT-Creation-Date: 2026-07-05 09:48+0530\n" +"PO-Revision-Date: 2026-07-05 09:48+0530\n" +"Last-Translator: eeshsaxena \n" +"Language-Team: Holidays Localization Team\n" +"Language: th\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 (half-day closing). +#, c-format +msgid "%s (half-day closing)" +msgstr "%s (ปิดครึ่งวัน)" + +#. Christmas Eve. +msgid "Christmas Eve" +msgstr "วันคริสต์มาสอีฟ" + +#. New Year's Eve. +msgid "New Year's Eve" +msgstr "วันสิ้นปี" diff --git a/tests/financial/test_london_stock_exchange.py b/tests/financial/test_london_stock_exchange.py index 8c7ce50764..26515fb977 100644 --- a/tests/financial/test_london_stock_exchange.py +++ b/tests/financial/test_london_stock_exchange.py @@ -21,6 +21,12 @@ class TestLondonStockExchange(CommonFinancialTests, TestCase): def setUpClass(cls): super().setUpClass(LondonStockExchange) + def test_code(self): + # LondonStockExchange derives from UnitedKingdom, so (like JPX/SSE) it + # keeps a ``country`` attribute set to None rather than removing it. + self.assertTrue(hasattr(self.holidays, "market")) + self.assertIsNone(getattr(self.holidays, "country", None)) + def test_market_aliases(self): self.assertAliases(LondonStockExchange, XLON, LSE) @@ -147,6 +153,6 @@ def test_2025(self): def test_2024_half_day(self): self.assertHalfDayHolidaysInYear( 2024, - ("2024-12-24", "Christmas Eve (early close)"), - ("2024-12-31", "New Year's Eve (early close)"), + ("2024-12-24", "Christmas Eve (half-day closing)"), + ("2024-12-31", "New Year's Eve (half-day closing)"), ) From 9616c6bc066c4e956ed13e3fb6ceff2ab13afef7 Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Thu, 9 Jul 2026 13:27:05 +0530 Subject: [PATCH 5/7] Address review: docstring, half-day label, and test suite cleanup Simplify the class docstring, rename the half-day label to 'markets close at 12:30pm' matching the requested phrasing, and consolidate the yearly test cases into a single representative year plus dedicated Christmas Eve/New Year's Eve and l10n tests. --- holidays/financial/london_stock_exchange.py | 34 ++--- holidays/locale/en_GB/LC_MESSAGES/XLON.po | 10 +- holidays/locale/en_US/LC_MESSAGES/XLON.po | 12 +- holidays/locale/th/LC_MESSAGES/XLON.po | 12 +- tests/financial/test_london_stock_exchange.py | 136 ++++++------------ 5 files changed, 74 insertions(+), 130 deletions(-) diff --git a/holidays/financial/london_stock_exchange.py b/holidays/financial/london_stock_exchange.py index 8c8be52282..6d92a0a729 100644 --- a/holidays/financial/london_stock_exchange.py +++ b/holidays/financial/london_stock_exchange.py @@ -18,15 +18,13 @@ class LondonStockExchange(ChildEntity, UnitedKingdom): - """London Stock Exchange holidays. + """London Stock Exchange (LSE) holidays. - The London Stock Exchange (LSE) is closed on the bank holidays observed in - England and Wales, so its public holidays are an alias of the England - (``ENG``) subdivision of the United Kingdom, including the one-off royal - bank holidays. + The London Stock Exchange is closed on the bank holidays observed in + England and Wales. On Christmas Eve and New Year's Eve the exchange runs a shortened trading - session (a half-day closing), available under the ``HALF_DAY`` category. + session. References: * @@ -41,21 +39,19 @@ class LondonStockExchange(ChildEntity, UnitedKingdom): supported_categories = (HALF_DAY, PUBLIC) start_year = 2000 - def _populate_half_day_holidays(self): - # On these days the exchange runs a shortened session (a 12:30 close), - # exposed here under the HALF_DAY category with a label so end users can - # tell it apart from a full market holiday. + def _populate_half_day_holidays(self) -> None: + # %s (markets close at 12:30pm). + close_12_30pm_label = tr("%s (markets close at 12:30pm)") - # %s (half-day closing). - half_day_closing_label = tr("%s (half-day closing)") + self._add_christmas_eve( + # Christmas Eve. + self._format_holiday_name(close_12_30pm_label, tr("Christmas Eve")) + ) - # Christmas Eve. - christmas_eve = self._format_holiday_name(half_day_closing_label, tr("Christmas Eve")) - self._add_christmas_eve(christmas_eve) - - # New Year's Eve. - new_years_eve = self._format_holiday_name(half_day_closing_label, tr("New Year's Eve")) - self._add_new_years_eve(new_years_eve) + self._add_new_years_eve( + # New Year's Eve. + self._format_holiday_name(close_12_30pm_label, tr("New Year's Eve")) + ) class XLON(LondonStockExchange): diff --git a/holidays/locale/en_GB/LC_MESSAGES/XLON.po b/holidays/locale/en_GB/LC_MESSAGES/XLON.po index 90f7986ef8..6626618d3d 100644 --- a/holidays/locale/en_GB/LC_MESSAGES/XLON.po +++ b/holidays/locale/en_GB/LC_MESSAGES/XLON.po @@ -10,14 +10,14 @@ # Website: https://github.com/vacanza/holidays # License: MIT (see LICENSE file) # -# London Stock Exchange holidays. +# London Stock Exchange (LSE) holidays. # msgid "" msgstr "" "Project-Id-Version: Holidays 0.100\n" "Report-Msgid-Bugs-To: l10n@vacanza.dev\n" -"POT-Creation-Date: 2026-07-05 09:48+0530\n" -"PO-Revision-Date: 2026-07-05 09:48+0530\n" +"POT-Creation-Date: 2026-07-09 00:00+0530\n" +"PO-Revision-Date: 2026-07-09 00:00+0530\n" "Last-Translator: eeshsaxena \n" "Language-Team: Holidays Localization Team\n" "Language: en_GB\n" @@ -27,9 +27,9 @@ msgstr "" "Generated-By: Lingva 5.0.6\n" "X-Source-Language: en_GB\n" -#. %s (half-day closing). +#. %s (markets close at 12:30pm). #, c-format -msgid "%s (half-day closing)" +msgid "%s (markets close at 12:30pm)" msgstr "" #. Christmas Eve. diff --git a/holidays/locale/en_US/LC_MESSAGES/XLON.po b/holidays/locale/en_US/LC_MESSAGES/XLON.po index e351f71b38..2d9666f4ba 100644 --- a/holidays/locale/en_US/LC_MESSAGES/XLON.po +++ b/holidays/locale/en_US/LC_MESSAGES/XLON.po @@ -10,14 +10,14 @@ # Website: https://github.com/vacanza/holidays # License: MIT (see LICENSE file) # -# London Stock Exchange holidays en_US localization. +# London Stock Exchange (LSE) holidays en_US localization. # msgid "" msgstr "" "Project-Id-Version: Holidays 0.100\n" "Report-Msgid-Bugs-To: l10n@vacanza.dev\n" -"POT-Creation-Date: 2026-07-05 09:48+0530\n" -"PO-Revision-Date: 2026-07-05 09:48+0530\n" +"POT-Creation-Date: 2026-07-09 00:00+0530\n" +"PO-Revision-Date: 2026-07-09 00:00+0530\n" "Last-Translator: eeshsaxena \n" "Language-Team: Holidays Localization Team\n" "Language: en_US\n" @@ -27,10 +27,10 @@ msgstr "" "Generated-By: Lingva 5.0.6\n" "X-Source-Language: en_GB\n" -#. %s (half-day closing). +#. %s (markets close at 12:30pm). #, c-format -msgid "%s (half-day closing)" -msgstr "%s (half-day closing)" +msgid "%s (markets close at 12:30pm)" +msgstr "%s (markets close at 12:30pm)" #. Christmas Eve. msgid "Christmas Eve" diff --git a/holidays/locale/th/LC_MESSAGES/XLON.po b/holidays/locale/th/LC_MESSAGES/XLON.po index 28c121d63f..cd0cd8af02 100644 --- a/holidays/locale/th/LC_MESSAGES/XLON.po +++ b/holidays/locale/th/LC_MESSAGES/XLON.po @@ -10,14 +10,14 @@ # Website: https://github.com/vacanza/holidays # License: MIT (see LICENSE file) # -# London Stock Exchange holidays th localization. +# London Stock Exchange (LSE) holidays th localization. # msgid "" msgstr "" "Project-Id-Version: Holidays 0.100\n" "Report-Msgid-Bugs-To: l10n@vacanza.dev\n" -"POT-Creation-Date: 2026-07-05 09:48+0530\n" -"PO-Revision-Date: 2026-07-05 09:48+0530\n" +"POT-Creation-Date: 2026-07-09 00:00+0530\n" +"PO-Revision-Date: 2026-07-09 00:00+0530\n" "Last-Translator: eeshsaxena \n" "Language-Team: Holidays Localization Team\n" "Language: th\n" @@ -27,10 +27,10 @@ msgstr "" "Generated-By: Lingva 5.0.6\n" "X-Source-Language: en_GB\n" -#. %s (half-day closing). +#. %s (markets close at 12:30pm). #, c-format -msgid "%s (half-day closing)" -msgstr "%s (ปิดครึ่งวัน)" +msgid "%s (markets close at 12:30pm)" +msgstr "%s (ตลาดปิดเวลา 12:30 น.)" #. Christmas Eve. msgid "Christmas Eve" diff --git a/tests/financial/test_london_stock_exchange.py b/tests/financial/test_london_stock_exchange.py index 26515fb977..bc997f9257 100644 --- a/tests/financial/test_london_stock_exchange.py +++ b/tests/financial/test_london_stock_exchange.py @@ -22,8 +22,6 @@ def setUpClass(cls): super().setUpClass(LondonStockExchange) def test_code(self): - # LondonStockExchange derives from UnitedKingdom, so (like JPX/SSE) it - # keeps a ``country`` attribute set to None rather than removing it. self.assertTrue(hasattr(self.holidays, "market")) self.assertIsNone(getattr(self.holidays, "country", None)) @@ -33,66 +31,10 @@ def test_market_aliases(self): def test_no_holidays(self): self.assertNoHolidays(LondonStockExchange(years=1999)) - def test_2002(self): - self.assertHolidays( - LondonStockExchange(years=2002), - ("2002-01-01", "New Year's Day"), - ("2002-03-29", "Good Friday"), - ("2002-04-01", "Easter Monday"), - ("2002-05-06", "May Day"), - ("2002-06-03", "Golden Jubilee of Elizabeth II"), - ("2002-06-04", "Spring Bank Holiday"), - ("2002-08-26", "Late Summer Bank Holiday"), - ("2002-12-25", "Christmas Day"), - ("2002-12-26", "Boxing Day"), - ) - - def test_2011(self): - self.assertHolidays( - LondonStockExchange(years=2011), - ("2011-01-01", "New Year's Day"), - ("2011-01-03", "New Year's Day (observed)"), - ("2011-04-22", "Good Friday"), - ("2011-04-25", "Easter Monday"), - ("2011-04-29", "Wedding of William and Catherine"), - ("2011-05-02", "May Day"), - ("2011-05-30", "Spring Bank Holiday"), - ("2011-08-29", "Late Summer Bank Holiday"), - ("2011-12-25", "Christmas Day"), - ("2011-12-26", "Boxing Day"), - ("2011-12-27", "Christmas Day (observed)"), - ) - - def test_2020(self): - self.assertHolidays( - LondonStockExchange(years=2020), - ("2020-01-01", "New Year's Day"), - ("2020-04-10", "Good Friday"), - ("2020-04-13", "Easter Monday"), - ("2020-05-08", "May Day"), - ("2020-05-25", "Spring Bank Holiday"), - ("2020-08-31", "Late Summer Bank Holiday"), - ("2020-12-25", "Christmas Day"), - ("2020-12-26", "Boxing Day"), - ("2020-12-28", "Boxing Day (observed)"), - ) - - def test_2021(self): - self.assertHolidays( - LondonStockExchange(years=2021), - ("2021-01-01", "New Year's Day"), - ("2021-04-02", "Good Friday"), - ("2021-04-05", "Easter Monday"), - ("2021-05-03", "May Day"), - ("2021-05-31", "Spring Bank Holiday"), - ("2021-08-30", "Late Summer Bank Holiday"), - ("2021-12-25", "Christmas Day"), - ("2021-12-26", "Boxing Day"), - ("2021-12-27", "Christmas Day (observed)"), - ("2021-12-28", "Boxing Day (observed)"), - ) - def test_2022(self): + # Exercises the royal one-off bank holidays alongside the regular + # England & Wales calendar; year-by-year correctness of the underlying + # calendar itself is covered by the United Kingdom test suite. self.assertHolidays( LondonStockExchange(years=2022), ("2022-01-01", "New Year's Day"), @@ -109,50 +51,56 @@ def test_2022(self): ("2022-12-27", "Christmas Day (observed)"), ) - def test_2023(self): - self.assertHolidays( - LondonStockExchange(years=2023), - ("2023-01-01", "New Year's Day"), - ("2023-01-02", "New Year's Day (observed)"), - ("2023-04-07", "Good Friday"), - ("2023-04-10", "Easter Monday"), - ("2023-05-01", "May Day"), - ("2023-05-08", "Coronation of Charles III"), - ("2023-05-29", "Spring Bank Holiday"), - ("2023-08-28", "Late Summer Bank Holiday"), - ("2023-12-25", "Christmas Day"), - ("2023-12-26", "Boxing Day"), - ) + def test_christmas_eve(self): + name = "Christmas Eve (markets close at 12:30pm)" + self.assertNoHolidayName(name) + self.assertHalfDayHolidayName(name, (f"{year}-12-24" for year in self.full_range)) - def test_2024(self): - self.assertHolidays( - LondonStockExchange(years=2024), + def test_new_years_eve(self): + name = "New Year's Eve (markets close at 12:30pm)" + self.assertNoHolidayName(name) + self.assertHalfDayHolidayName(name, (f"{year}-12-31" for year in self.full_range)) + + def test_l10n_default(self): + self.assertLocalizedHolidays( ("2024-01-01", "New Year's Day"), ("2024-03-29", "Good Friday"), ("2024-04-01", "Easter Monday"), ("2024-05-06", "May Day"), ("2024-05-27", "Spring Bank Holiday"), ("2024-08-26", "Late Summer Bank Holiday"), + ("2024-12-24", "Christmas Eve (markets close at 12:30pm)"), ("2024-12-25", "Christmas Day"), ("2024-12-26", "Boxing Day"), + ("2024-12-31", "New Year's Eve (markets close at 12:30pm)"), ) - def test_2025(self): - self.assertHolidays( - LondonStockExchange(years=2025), - ("2025-01-01", "New Year's Day"), - ("2025-04-18", "Good Friday"), - ("2025-04-21", "Easter Monday"), - ("2025-05-05", "May Day"), - ("2025-05-26", "Spring Bank Holiday"), - ("2025-08-25", "Late Summer Bank Holiday"), - ("2025-12-25", "Christmas Day"), - ("2025-12-26", "Boxing Day"), + def test_l10n_en_us(self): + self.assertLocalizedHolidays( + "en_US", + ("2024-01-01", "New Year's Day"), + ("2024-03-29", "Good Friday"), + ("2024-04-01", "Easter Monday"), + ("2024-05-06", "May Day"), + ("2024-05-27", "Spring Bank Holiday"), + ("2024-08-26", "Late Summer Bank Holiday"), + ("2024-12-24", "Christmas Eve (markets close at 12:30pm)"), + ("2024-12-25", "Christmas Day"), + ("2024-12-26", "Boxing Day"), + ("2024-12-31", "New Year's Eve (markets close at 12:30pm)"), ) - def test_2024_half_day(self): - self.assertHalfDayHolidaysInYear( - 2024, - ("2024-12-24", "Christmas Eve (half-day closing)"), - ("2024-12-31", "New Year's Eve (half-day closing)"), + def test_l10n_th(self): + self.assertLocalizedHolidays( + "th", + ("2024-01-01", "วันขึ้นปีใหม่"), + ("2024-03-29", "วันศุกร์ประเสริฐ"), + ("2024-04-01", "วันจันทร์อีสเตอร์"), + ("2024-05-06", "วันเมย์เดย์"), + ("2024-05-27", "วันหยุดฤดูใบไม้ผลิของธนาคาร"), + ("2024-08-26", "วันหยุดช่วงปลายฤดูร้อนของธนาคาร"), + ("2024-12-24", "วันคริสต์มาสอีฟ (ตลาดปิดเวลา 12:30 น.)"), + ("2024-12-25", "วันคริสต์มาส"), + ("2024-12-26", "วันเปิดกล่องของขวัญ"), + ("2024-12-31", "วันสิ้นปี (ตลาดปิดเวลา 12:30 น.)"), ) From 9ae5b15cf504f09a2e85bdb1576fb773e6b44f6e Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Thu, 9 Jul 2026 22:54:59 +0530 Subject: [PATCH 6/7] Use assertHolidaysInYear for 2022 test and bump .po version to 0.101 --- holidays/locale/en_GB/LC_MESSAGES/XLON.po | 2 +- holidays/locale/en_US/LC_MESSAGES/XLON.po | 2 +- holidays/locale/th/LC_MESSAGES/XLON.po | 2 +- tests/financial/test_london_stock_exchange.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/holidays/locale/en_GB/LC_MESSAGES/XLON.po b/holidays/locale/en_GB/LC_MESSAGES/XLON.po index 6626618d3d..e861cf0544 100644 --- a/holidays/locale/en_GB/LC_MESSAGES/XLON.po +++ b/holidays/locale/en_GB/LC_MESSAGES/XLON.po @@ -14,7 +14,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Holidays 0.100\n" +"Project-Id-Version: Holidays 0.101\n" "Report-Msgid-Bugs-To: l10n@vacanza.dev\n" "POT-Creation-Date: 2026-07-09 00:00+0530\n" "PO-Revision-Date: 2026-07-09 00:00+0530\n" diff --git a/holidays/locale/en_US/LC_MESSAGES/XLON.po b/holidays/locale/en_US/LC_MESSAGES/XLON.po index 2d9666f4ba..a566818817 100644 --- a/holidays/locale/en_US/LC_MESSAGES/XLON.po +++ b/holidays/locale/en_US/LC_MESSAGES/XLON.po @@ -14,7 +14,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Holidays 0.100\n" +"Project-Id-Version: Holidays 0.101\n" "Report-Msgid-Bugs-To: l10n@vacanza.dev\n" "POT-Creation-Date: 2026-07-09 00:00+0530\n" "PO-Revision-Date: 2026-07-09 00:00+0530\n" diff --git a/holidays/locale/th/LC_MESSAGES/XLON.po b/holidays/locale/th/LC_MESSAGES/XLON.po index cd0cd8af02..a0663c0aa4 100644 --- a/holidays/locale/th/LC_MESSAGES/XLON.po +++ b/holidays/locale/th/LC_MESSAGES/XLON.po @@ -14,7 +14,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Holidays 0.100\n" +"Project-Id-Version: Holidays 0.101\n" "Report-Msgid-Bugs-To: l10n@vacanza.dev\n" "POT-Creation-Date: 2026-07-09 00:00+0530\n" "PO-Revision-Date: 2026-07-09 00:00+0530\n" diff --git a/tests/financial/test_london_stock_exchange.py b/tests/financial/test_london_stock_exchange.py index bc997f9257..85eda7335f 100644 --- a/tests/financial/test_london_stock_exchange.py +++ b/tests/financial/test_london_stock_exchange.py @@ -35,8 +35,8 @@ def test_2022(self): # Exercises the royal one-off bank holidays alongside the regular # England & Wales calendar; year-by-year correctness of the underlying # calendar itself is covered by the United Kingdom test suite. - self.assertHolidays( - LondonStockExchange(years=2022), + self.assertHolidaysInYear( + 2022, ("2022-01-01", "New Year's Day"), ("2022-01-03", "New Year's Day (observed)"), ("2022-04-15", "Good Friday"), From 0e8d186690355d5e92b60672f9056578122b4518 Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Tue, 14 Jul 2026 18:31:16 +0530 Subject: [PATCH 7/7] Drop weekend bank holidays and shift half-days to the preceding Friday The exchange does not trade at weekends, so a bank holiday falling on a Saturday or Sunday is not a trading day in its own right; only its observed weekday substitute is. Suppress those inherited dates with SAT_TO_NONE + SUN_TO_NONE, following the approach used for SIX. The shortened Christmas Eve and New Year's Eve sessions likewise move back to the preceding Friday when the eve falls on a weekend, matching the published LSE calendar (2011: Dec 23 and Dec 30). --- holidays/financial/london_stock_exchange.py | 34 ++++++++++++++----- tests/financial/test_london_stock_exchange.py | 28 ++++++++++++--- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/holidays/financial/london_stock_exchange.py b/holidays/financial/london_stock_exchange.py index 6d92a0a729..c44037ef4a 100644 --- a/holidays/financial/london_stock_exchange.py +++ b/holidays/financial/london_stock_exchange.py @@ -15,6 +15,7 @@ from holidays.constants import HALF_DAY, PUBLIC from holidays.countries.united_kingdom import UnitedKingdom from holidays.mixins.child_entity import ChildEntity +from holidays.observed_holiday_base import SAT_SUN_TO_PREV_FRI, SAT_TO_NONE, SUN_TO_NONE class LondonStockExchange(ChildEntity, UnitedKingdom): @@ -43,15 +44,32 @@ def _populate_half_day_holidays(self) -> None: # %s (markets close at 12:30pm). close_12_30pm_label = tr("%s (markets close at 12:30pm)") - self._add_christmas_eve( - # Christmas Eve. - self._format_holiday_name(close_12_30pm_label, tr("Christmas Eve")) - ) + for dt in ( + self._add_christmas_eve( + # Christmas Eve. + self._format_holiday_name(close_12_30pm_label, tr("Christmas Eve")) + ), + self._add_new_years_eve( + # New Year's Eve. + self._format_holiday_name(close_12_30pm_label, tr("New Year's Eve")) + ), + ): + # The shortened session moves to the preceding Friday when the eve falls + # on a weekend, since the exchange does not trade on Saturday or Sunday. + self._move_holiday(dt, rule=SAT_SUN_TO_PREV_FRI, show_observed_label=False) - self._add_new_years_eve( - # New Year's Eve. - self._format_holiday_name(close_12_30pm_label, tr("New Year's Eve")) - ) + def _populate(self, year: int) -> None: + super()._populate(year) + + # The exchange is closed at weekends, so a bank holiday that falls on a + # Saturday or Sunday is not a trading day in its own right; only its + # observed weekday substitute is. + if self.observed: + for dt in tuple(self.keys()): + if dt.year == year: + self._move_holiday( + dt, rule=SAT_TO_NONE + SUN_TO_NONE, show_observed_label=False + ) class XLON(LondonStockExchange): diff --git a/tests/financial/test_london_stock_exchange.py b/tests/financial/test_london_stock_exchange.py index 85eda7335f..d7bedc4fbf 100644 --- a/tests/financial/test_london_stock_exchange.py +++ b/tests/financial/test_london_stock_exchange.py @@ -35,9 +35,10 @@ def test_2022(self): # Exercises the royal one-off bank holidays alongside the regular # England & Wales calendar; year-by-year correctness of the underlying # calendar itself is covered by the United Kingdom test suite. + # New Year's Day (Sat) and Christmas Day (Sun) are not trading days in their + # own right, so only their observed weekday substitutes appear. self.assertHolidaysInYear( 2022, - ("2022-01-01", "New Year's Day"), ("2022-01-03", "New Year's Day (observed)"), ("2022-04-15", "Good Friday"), ("2022-04-18", "Easter Monday"), @@ -46,20 +47,39 @@ def test_2022(self): ("2022-06-03", "Platinum Jubilee of Elizabeth II"), ("2022-08-29", "Late Summer Bank Holiday"), ("2022-09-19", "State Funeral of Queen Elizabeth II"), - ("2022-12-25", "Christmas Day"), ("2022-12-26", "Boxing Day"), ("2022-12-27", "Christmas Day (observed)"), ) + def test_weekend_holidays_are_not_trading_days(self): + # The exchange is shut at weekends, so a bank holiday landing on a Saturday + # or Sunday is dropped and only its observed substitute remains. + self.assertNoHoliday("2011-01-01", "2011-12-25", "2022-01-01", "2022-12-25") + self.assertHoliday("2011-01-03", "2011-12-27", "2022-01-03", "2022-12-27") + def test_christmas_eve(self): name = "Christmas Eve (markets close at 12:30pm)" self.assertNoHolidayName(name) - self.assertHalfDayHolidayName(name, (f"{year}-12-24" for year in self.full_range)) + self.assertHalfDayHolidayName(name, self.full_range) + # Moved back to the preceding Friday when Dec 24 falls on a weekend. + self.assertHalfDayHolidayName( + name, + "2011-12-23", # Dec 24 fell on a Saturday. + "2017-12-22", # Dec 24 fell on a Sunday. + "2024-12-24", # Dec 24 fell on a Tuesday. + ) def test_new_years_eve(self): name = "New Year's Eve (markets close at 12:30pm)" self.assertNoHolidayName(name) - self.assertHalfDayHolidayName(name, (f"{year}-12-31" for year in self.full_range)) + self.assertHalfDayHolidayName(name, self.full_range) + # Moved back to the preceding Friday when Dec 31 falls on a weekend. + self.assertHalfDayHolidayName( + name, + "2011-12-30", # Dec 31 fell on a Saturday. + "2017-12-29", # Dec 31 fell on a Sunday. + "2024-12-31", # Dec 31 fell on a Tuesday. + ) def test_l10n_default(self): self.assertLocalizedHolidays(