Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2003,6 +2003,13 @@ code when available. The following financial markets are available:
<td></td>
</tr>
<tr>
<td>Johannesburg Stock Exchange</td>
<td>XJSE</td>
<td>Johannesburg Stock Exchange (JSE) market holidays</td>
<td></td>
<td>HALF_DAY</td>
</tr>
<tr>
<td>NASDAQ</td>
<td>XNAS</td>
<td>National Association of Securities Dealers Automated Quotations (NASDAQ) holidays</td>
Expand Down
1 change: 1 addition & 0 deletions holidays/financial/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,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.johannesburg_stock_exchange import JohannesburgStockExchange, JSE, XJSE
from holidays.financial.nasdaq import NASDAQ, XNAS
from holidays.financial.national_stock_exchange_of_india import (
NationalStockExchangeOfIndia,
Expand Down
72 changes: 72 additions & 0 deletions holidays/financial/johannesburg_stock_exchange.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# 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 holidays.constants import HALF_DAY, PUBLIC
from holidays.countries.south_africa import SouthAfrica
from holidays.observed_holiday_base import SAT_SUN_TO_NONE


class JohannesburgStockExchange(SouthAfrica):
"""Johannesburg Stock Exchange (JSE) holidays.

References:
[2019](https://web.archive.org/web/20230103093400/https://clientportal.jse.co.za/Content/JSE%20Trading%20Dates%20and%20Calendars%20Items/JSE%20Market%20Notice%202019%20Markets%20Calendar.pdf)
[2020](https://web.archive.org/web/20220123212248/https://clientportal.jse.co.za/Content/JSE%20Trading%20Dates%20and%20Calendars%20Items/JSE%20Market%20Notice%2030319%20All%20Markets%20-%20Calendar%202020.pdf)
[2021](https://web.archive.org/web/20220123222115/https://clientportal.jse.co.za/Content/JSE%20Trading%20Dates%20and%20Calendars%20Items/JSE%20Market%20Notice%2051720%20All%20Markets%20-%20Updated%20JSE%20Markets%20Calendar%202021.pdf)
[2022](https://web.archive.org/web/20250914180247/https://clientportal.jse.co.za/Content/JSE%20Trading%20Dates%20and%20Calendars%20Items/JSE%20Markets%20Calendar%202022%20Market%20Notice%20updated.pdf)
[2023](https://clientportal.jse.co.za/Content/JSE%20Trading%20Dates%20and%20Calendars%20Items/JSE%20Market%20Notice%2051122%20All%20Markets%20-%20JSE%20Markets%20Calendar%202023.pdf)
Comment thread
KJhellico marked this conversation as resolved.
Outdated
[2024](https://web.archive.org/web/20240614114810/https://clientportal.jse.co.za/Content/JSE%20Trading%20Dates%20and%20Calendars%20Items/JSE%20Market%20Notice%2006124%20All%20Markets%20-%20JSE%20Markets%20Calendar%202024%20-%20Updated.pdf)
[2025](https://web.archive.org/web/20251122211135/https://clientportal.jse.co.za/Content/JSE%20Trading%20Dates%20and%20Calendars%20Items/JSE%20Market%20Notice%2030524%20All%20Markets%20-%20JSE%20Markets%20Calendar%202025.pdf)
[2026](https://web.archive.org/web/20260123013926/https://clientportal.jse.co.za/Content/JSE%20Trading%20Dates%20and%20Calendars%20Items/JSE%20Market%20Notice%2038025%20All%20Markets%20-%20JSE%20Markets%20Calendar%202026.pdf)
"""

country = None # type: ignore[assignment]
market = "XJSE"
parent_entity = SouthAfrica
supported_categories: tuple[str, ...] = (HALF_DAY, PUBLIC) # type: ignore[assignment]
start_year = 2000
observed_label = "%s"

def _populate_public_holidays(self):
super()._populate_public_holidays()

for dt in tuple(self):
Comment thread
KJhellico marked this conversation as resolved.
if self._is_weekend(dt):
self.pop(dt)

def _populate_half_day_holidays(self):
# %s (markets close at 12:00 p.m. SAST).
pause_label = self.tr("%s (markets close at 12:00 p.m. SAST)")
Comment thread
KJhellico marked this conversation as resolved.
Outdated

self._move_holiday(
# Christmas Eve.
self._add_christmas_eve(
self._format_holiday_name(pause_label, self.tr("Christmas Eve"))
),
rule=SAT_SUN_TO_NONE,
)

self._move_holiday(
# New Year's Eve.
self._add_new_years_eve(
self._format_holiday_name(pause_label, self.tr("New Year's Eve"))
),
rule=SAT_SUN_TO_NONE,
)
Comment thread
KJhellico marked this conversation as resolved.


class XJSE(JohannesburgStockExchange):
pass


class JSE(JohannesburgStockExchange):
pass
1 change: 1 addition & 0 deletions holidays/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@
"hong_kong_stock_exchange": ("HongKongStockExchange", "XHKG", "HKEX", "SEHK"),
"ice_futures_europe": ("IceFuturesEurope", "IFEU", "ICEFuturesEurope"),
"japan_exchange": ("JapanExchange", "XJPX", "JPX", "TSE", "OSE"),
"johannesburg_stock_exchange": ("JohannesburgStockExchange", "XJSE", "JSE"),
"nasdaq": ("NASDAQ", "XNAS"),
"national_stock_exchange_of_india": ("NationalStockExchangeOfIndia", "XNSE", "NSE"),
"ny_stock_exchange": ("NewYorkStockExchange", "XNYS", "NYSE"),
Expand Down
89 changes: 89 additions & 0 deletions tests/financial/test_johannesburg_stock_exchange.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# 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.financial.johannesburg_stock_exchange import JohannesburgStockExchange
from tests.common import CommonFinancialTests


class TestJohannesburgStockExchange(CommonFinancialTests, TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass(JohannesburgStockExchange)

def test_code(self):
self.assertTrue(hasattr(self.holidays, "market"))
self.assertIsNone(getattr(self.holidays, "country", None))

def test_christmas_eve(self):
name = "Christmas Eve (markets close at 12:00 p.m. SAST)"
self.assertNoHolidayName(name)
self.assertHalfDayNonObservedHolidayName(
Comment thread
KJhellico marked this conversation as resolved.
Comment thread
KJhellico marked this conversation as resolved.
name, (f"{year}-12-24" for year in self.full_range)
)
self.assertHalfDayHolidayName(
name,
"2020-12-24",
"2021-12-24",
"2024-12-24",
"2025-12-24",
"2026-12-24",
)
self.assertNoHalfDayHolidayName(
name,
"2022-12-24",
"2023-12-24",
)

def test_new_years_eve(self):
name = "New Year's Eve (markets close at 12:00 p.m. SAST)"
self.assertNoHolidayName(name)
self.assertHalfDayNonObservedHolidayName(
name, (f"{year}-12-31" for year in self.full_range)
)
self.assertHalfDayHolidayName(
name,
"2020-12-31",
"2021-12-31",
"2024-12-31",
"2025-12-31",
"2026-12-31",
)
self.assertNoHalfDayHolidayName(
name,
"2022-12-31",
"2023-12-31",
)

def test_2025(self):
self.assertHolidaysInYear(
2025,
("2025-01-01", "New Year's Day"),
("2025-03-21", "Human Rights Day"),
("2025-04-18", "Good Friday"),
("2025-04-21", "Family Day"),
("2025-04-28", "Freedom Day"),
("2025-05-01", "Workers' Day"),
("2025-06-16", "Youth Day"),
("2025-09-24", "Heritage Day"),
("2025-12-16", "Day of Reconciliation"),
("2025-12-25", "Christmas Day"),
("2025-12-26", "Day of Goodwill"),
)

def test_half_day_2025(self):
self.assertHalfDayHolidaysInYear(
2025,
("2025-12-24", "Christmas Eve (markets close at 12:00 p.m. SAST)"),
("2025-12-31", "New Year's Eve (markets close at 12:00 p.m. SAST)"),
)