Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -2045,6 +2045,13 @@ code when available. The following financial markets are available:
<td></td>
</tr>
<tr>
<td>Singapore Exchange</td>
<td>XSES</td>
<td>Singapore Exchange (SGX) market holidays</td>
<td><strong>en_SG</strong>, en_US, th</td>
<td>HALF_DAY</td>
</tr>
<tr>
<td>SIX Swiss Exchange</td>
<td>XSWX</td>
<td>SIX Swiss Exchange market 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 @@ -29,5 +29,6 @@
from holidays.financial.ny_stock_exchange import NewYorkStockExchange, XNYS, NYSE
from holidays.financial.shanghai_stock_exchange import ShanghaiStockExchange, XSHG, SSE
from holidays.financial.shenzhen_stock_exchange import ShenzhenStockExchange, XSHE, SZSE
from holidays.financial.singapore_exchange import SingaporeExchange, XSES, SGX
from holidays.financial.six_swiss_exchange import SIXSwissExchange, XSWX, SIX
from holidays.financial.toronto_stock_exchange import TorontoStockExchange, XTSE, TSX
71 changes: 71 additions & 0 deletions holidays/financial/singapore_exchange.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# 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.constants import HALF_DAY, PUBLIC
from holidays.countries.singapore import Singapore
from holidays.observed_holiday_base import SAT_SUN_TO_NONE


class SingaporeExchange(Singapore):
"""Singapore Exchange (SGX) holidays.

References:
<https://web.archive.org/web/20260725102849/https://www.sgx.com/stock-exchange/trading>
Comment thread
KJhellico marked this conversation as resolved.
Outdated
"""

country = None # type: ignore[assignment]
market = "XSES"
parent_entity = Singapore
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.
Outdated
if self._is_weekend(dt):
self.pop(dt)

def _populate_half_day_holidays(self):
# %s (markets close at 12:00 p.m. SGT).
pause_label = tr("%s (markets close at 12:00 p.m. SGT)")

self._move_holiday(
Comment thread
KJhellico marked this conversation as resolved.
Outdated
# Christmas Eve.
self._add_christmas_eve(self._format_holiday_name(pause_label, 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, tr("New Year's Eve"))),
rule=SAT_SUN_TO_NONE,
)

self._move_holiday(
self._add_chinese_new_years_eve(
# Chinese New Year's Eve.
self._format_holiday_name(pause_label, tr("Chinese New Year's Eve"))
),
rule=SAT_SUN_TO_NONE,
)


class XSES(SingaporeExchange):
pass


class SGX(SingaporeExchange):
pass
45 changes: 45 additions & 0 deletions holidays/locale/en_SG/LC_MESSAGES/XSES.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# 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)
#
# Singapore Exchange (SGX) holidays.
#
msgid ""
msgstr ""
"Project-Id-Version: Holidays 0.102\n"
"Report-Msgid-Bugs-To: l10n@vacanza.dev\n"
"POT-Creation-Date: 2026-07-25 04:57+0000\n"
"PO-Revision-Date: 2026-07-25 14:54+0000\n"
"Last-Translator: Paresh Joshi <pareshjoshij@gmail.com>\n"
"Language-Team: Holidays Localization Team\n"
"Language: en_SG\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_SG\n"

#. %s (markets close at 12:00 p.m. SGT).
#, c-format
msgid "%s (markets close at 12:00 p.m. SGT)"
msgstr ""

#. Christmas Eve.
msgid "Christmas Eve"
msgstr ""

#. New Year's Eve.
msgid "New Year's Eve"
msgstr ""

#. Chinese New Year's Eve.
msgid "Chinese New Year's Eve"
msgstr ""
45 changes: 45 additions & 0 deletions holidays/locale/en_US/LC_MESSAGES/XSES.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# 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)
#
# Singapore Exchange (SGX) holidays en_US localization.
#
msgid ""
msgstr ""
"Project-Id-Version: Holidays 0.102\n"
"Report-Msgid-Bugs-To: l10n@vacanza.dev\n"
"POT-Creation-Date: 2026-07-25 04:57+0000\n"
"PO-Revision-Date: 2026-07-25 14:54+0000\n"
"Last-Translator: Paresh Joshi <pareshjoshij@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_SG\n"

#. %s (markets close at 12:00 p.m. SGT).
#, c-format
msgid "%s (markets close at 12:00 p.m. SGT)"
msgstr "%s (markets close at 12:00 p.m. SGT)"

#. Christmas Eve.
msgid "Christmas Eve"
msgstr "Christmas Eve"

#. New Year's Eve.
msgid "New Year's Eve"
msgstr "New Year's Eve"

#. Chinese New Year's Eve.
msgid "Chinese New Year's Eve"
msgstr "Chinese New Year's Eve"
45 changes: 45 additions & 0 deletions holidays/locale/th/LC_MESSAGES/XSES.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# 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)
#
# Singapore Exchange (SGX) holidays th localization.
#
msgid ""
msgstr ""
"Project-Id-Version: Holidays 0.102\n"
"Report-Msgid-Bugs-To: l10n@vacanza.dev\n"
"POT-Creation-Date: 2026-07-25 04:57+0000\n"
"PO-Revision-Date: 2026-07-25 14:54+0000\n"
"Last-Translator: Paresh Joshi <pareshjoshij@gmail.com>\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_SG\n"

#. %s (markets close at 12:00 p.m. SGT).
#, c-format
msgid "%s (markets close at 12:00 p.m. SGT)"
msgstr "%s (ตลาดปิดเวลา 12:00 น. SGT)"

#. Christmas Eve.
msgid "Christmas Eve"
msgstr "วันคริสต์มาสอีฟ"

#. New Year's Eve.
msgid "New Year's Eve"
msgstr "วันสิ้นปี"

#. Chinese New Year's Eve.
msgid "Chinese New Year's Eve"
msgstr "วันสิ้นปีจีน"
Comment thread
KJhellico marked this conversation as resolved.
Outdated
1 change: 1 addition & 0 deletions holidays/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@
"ny_stock_exchange": ("NewYorkStockExchange", "XNYS", "NYSE"),
"shanghai_stock_exchange": ("ShanghaiStockExchange", "XSHG", "SSE"),
"shenzhen_stock_exchange": ("ShenzhenStockExchange", "XSHE", "SZSE"),
"singapore_exchange": ("SingaporeExchange", "XSES", "SGX"),
"six_swiss_exchange": ("SIXSwissExchange", "XSWX", "SIX"),
"toronto_stock_exchange": ("TorontoStockExchange", "XTSE", "TSX"),
}
Expand Down
105 changes: 105 additions & 0 deletions tests/financial/test_singapore_exchange.py
Comment thread
KJhellico marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# 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.singapore_exchange import SingaporeExchange
from tests.common import CommonFinancialTests


class TestSingaporeExchange(CommonFinancialTests, TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass(SingaporeExchange)

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. SGT)"
self.assertNoHolidayName(name)
self.assertHalfDayNonObservedHolidayName(
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. SGT)"
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_chinese_new_years_eve(self):
name = "Chinese New Year's Eve (markets close at 12:00 p.m. SGT)"
self.assertNoHolidayName(name)
self.assertHalfDayHolidayName(
name,
"2020-01-24",
"2021-02-11",
"2022-01-31",
"2024-02-09",
"2025-01-28",
"2026-02-16",
)
self.assertNoHalfDayHolidayName(
name,
"2023-01-21",
)

def test_2025(self):
self.assertHolidaysInYear(
2025,
("2025-01-01", "New Year's Day"),
("2025-01-29", "Chinese New Year"),
("2025-01-30", "Chinese New Year"),
("2025-03-31", "Hari Raya Puasa"),
("2025-04-18", "Good Friday"),
("2025-05-01", "Labour Day"),
("2025-05-12", "Vesak Day"),
("2025-10-20", "Deepavali"),
("2025-12-25", "Christmas Day"),
)

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