+
Skip to content

Conversation

Kartik-kodes
Copy link

@Kartik-kodes Kartik-kodes commented Oct 8, 2025

Proposed change

This pull request adds support for half-day holidays for the New York Stock Exchange (NYSE), including the day before Independence Day, the day after Thanksgiving, and Christmas Eve.
Resolves #2976.

Type of change

  • 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

Signed-off-by: Kartik Agarwal <kartikk1407@gmail.com>
Copy link
Contributor

coderabbitai bot commented Oct 8, 2025

Summary by CodeRabbit

  • New Features
    • NYSE calendars now include half-day market sessions.
    • Half days are recognized for:
      • The day before Independence Day (when applicable)
      • The day after Thanksgiving
      • Christmas Eve (when Christmas Day falls on a weekday)
    • Half-day labels are clearly indicated in results for easier identification.
    • These entries are automatically included alongside existing holidays without changing full-day holiday behavior.

Walkthrough

Adds HALF_DAY constant import. Introduces NewYorkStockExchange._populate_half_day_holidays to register NYSE half-day holidays (pre–Independence Day, day after Thanksgiving, Christmas Eve when Christmas Day is a weekday). Invokes this method from _populate_public_holidays to include half-day entries without altering existing full-day holiday definitions.

Changes

Cohort / File(s) Summary of changes
NYSE half-day holiday handling
holidays/financial/ny_stock_exchange.py
Imported HALF_DAY. Added _populate_half_day_holidays to define three half-day cases and label them using HALF_DAY. Called the new method from _populate_public_holidays to populate half-day holiday entries.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

test

Suggested reviewers

  • PPsyrius
  • KJhellico

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Linked Issues Check ⚠️ Warning While the PR implements half-day holiday logic, it does not include any updates to tests/common.py to expand label tests for financial entities as required by issue #2876, so it fails to satisfy the primary objectives. Please add or update tests in tests/common.py to expand label verification for financial entities and ensure the new half-day holiday labels are covered as specified in issue #2876.
Out of Scope Changes Check ⚠️ Warning The PR introduces new half-day holiday implementation for the NYSE, which is unrelated to the linked issue’s goal of expanding common label tests, thereby including out-of-scope functionality. Split this PR into two: one focused on updating common label tests for financial entities per issue #2876 and a separate feature PR for the NYSE half-day holiday implementation.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title “feat: Add NYSE half-day holidays” succinctly and accurately describes the main change in the pull request by highlighting the addition of half-day holiday support for the New York Stock Exchange.
Description Check ✅ Passed The pull request description directly addresses the addition of half-day holidays for the New York Stock Exchange by naming the specific days and referencing the related issue, which matches the changes summarized in the diff without veering off-topic.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

sonarqubecloud bot commented Oct 8, 2025

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff20a26 and ab04c3c.

📒 Files selected for processing (1)
  • holidays/financial/ny_stock_exchange.py (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
holidays/financial/ny_stock_exchange.py (5)
holidays/countries/china.py (1)
  • _populate_half_day_holidays (190-203)
holidays/countries/turkey.py (1)
  • _populate_half_day_holidays (109-120)
holidays/countries/curacao.py (1)
  • _populate_half_day_holidays (159-166)
holidays/countries/greece.py (1)
  • _populate_half_day_holidays (91-96)
holidays/countries/iceland.py (1)
  • _populate_half_day_holidays (82-90)
🔇 Additional comments (2)
holidays/financial/ny_stock_exchange.py (2)

32-32: LGTM on the import.

The HALF_DAY constant import is appropriate for the half-day holiday implementation.


144-162: PR objectives mismatch.

The PR claims to fix issue #2876, which is about expanding label tests for financial entities. However, this PR adds actual half-day holiday functionality rather than test updates. The linked issue and the actual changes don't align.

# XMAS DAY: Dec 25th - every year
self._move_holiday(self._add_christmas_day("Christmas Day"))

self._populate_half_day_holidays()
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the class structure.

The method call looks correct, but the method definition at line 144 has a critical indentation issue that will cause an AttributeError at runtime.

Run this script to confirm the indentation problem:


🏁 Script executed:

#!/bin/bash
# Verify that _populate_half_day_holidays is properly indented as a class method

# Check the indentation of the method definition
rg -n "^def _populate_half_day_holidays" holidays/financial/ny_stock_exchange.py

# Show the method definition with context to verify it's inside the class
rg -n -B2 -A2 "def _populate_half_day_holidays" holidays/financial/ny_stock_exchange.py

Length of output: 273


Indent _populate_half_day_holidays inside the NYStockExchange class
holidays/financial/ny_stock_exchange.py:144 must be indented to match other method definitions so it’s a proper class method.

🤖 Prompt for AI Agents
In holidays/financial/ny_stock_exchange.py around lines 126 and 144, the call to
self._populate_half_day_holidays() and the method definition at line 144 are
mis-indented; indent the _populate_half_day_holidays method definition to the
same indentation level as the other methods inside the NYStockExchange class so
it becomes a proper instance method, and ensure the call remains inside the
class (using the same indentation level as other method bodies).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self._populate_half_day_holidays()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PPsyrius, here's the properly indented method definition:

    def _populate_half_day_holidays(self):
        # Half-day holidays (market closes at 13:00).
        # Source: https://www.nyse.com/markets/hours-calendars
        name_half_day = " ({})".format(HALF_DAY)

        # Day before Independence Day (July 3rd).
        if self._is_weekday(JUL, 4):
            self._add_holiday_jul_3("Day before Independence Day" + name_half_day)

        # Day after Thanksgiving (aka Black Friday).
        self._add_holiday_1_day_past_4th_thu_of_nov(
            "Day after Thanksgiving" + name_half_day
        )

        # Christmas Eve.
        # If Christmas Day is on a weekday, Christmas Eve is a half-day.
        if self._is_weekday(DEC, 25):
            self._add_holiday_dec_24("Christmas Eve" + name_half_day)

The method needs to be indented with 4 spaces to align with other methods in the NewYorkStockExchange class.

Comment on lines +144 to +162
def _populate_half_day_holidays(self):
# Half-day holidays (market closes at 13:00).
# Source: https://www.nyse.com/markets/hours-calendars
name_half_day = " ({})".format(HALF_DAY)

# Day before Independence Day (July 3rd).
if self._is_weekday(JUL, 4):
self._add_holiday_jul_3("Day before Independence Day" + name_half_day)

# Day after Thanksgiving (aka Black Friday).
self._add_holiday_1_day_past_4th_thu_of_nov(
"Day after Thanksgiving" + name_half_day
)

# Christmas Eve.
# If Christmas Day is on a weekday, Christmas Eve is a half-day.
if self._is_weekday(DEC, 25):
self._add_holiday_dec_24("Christmas Eve" + name_half_day)

Copy link
Contributor

@coderabbitai coderabbitai bot Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix critical indentation error.

The method is defined at module level instead of as a class method. This will cause an AttributeError when _populate_public_holidays() tries to call self._populate_half_day_holidays() at line 126.

Apply this diff to fix the indentation:

-def _populate_half_day_holidays(self):
-        # Half-day holidays (market closes at 13:00).
-        # Source: https://www.nyse.com/markets/hours-calendars
-        name_half_day = " ({})".format(HALF_DAY)
-
-        # Day before Independence Day (July 3rd).
-        if self._is_weekday(JUL, 4):
-            self._add_holiday_jul_3("Day before Independence Day" + name_half_day)
-
-        # Day after Thanksgiving (aka Black Friday).
-        self._add_holiday_1_day_past_4th_thu_of_nov(
-            "Day after Thanksgiving" + name_half_day
-        )
-
-        # Christmas Eve.
-        # If Christmas Day is on a weekday, Christmas Eve is a half-day.
-        if self._is_weekday(DEC, 25):
-            self._add_holiday_dec_24("Christmas Eve" + name_half_day)
+    def _populate_half_day_holidays(self):
+        # Half-day holidays (market closes at 13:00).
+        # Source: https://www.nyse.com/markets/hours-calendars
+        name_half_day = " ({})".format(HALF_DAY)
+
+        # Day before Independence Day (July 3rd).
+        if self._is_weekday(JUL, 4):
+            self._add_holiday_jul_3("Day before Independence Day" + name_half_day)
+
+        # Day after Thanksgiving (aka Black Friday).
+        self._add_holiday_1_day_past_4th_thu_of_nov(
+            "Day after Thanksgiving" + name_half_day
+        )
+
+        # Christmas Eve.
+        # If Christmas Day is on a weekday, Christmas Eve is a half-day.
+        if self._is_weekday(DEC, 25):
+            self._add_holiday_dec_24("Christmas Eve" + name_half_day)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _populate_half_day_holidays(self):
# Half-day holidays (market closes at 13:00).
# Source: https://www.nyse.com/markets/hours-calendars
name_half_day = " ({})".format(HALF_DAY)
# Day before Independence Day (July 3rd).
if self._is_weekday(JUL, 4):
self._add_holiday_jul_3("Day before Independence Day" + name_half_day)
# Day after Thanksgiving (aka Black Friday).
self._add_holiday_1_day_past_4th_thu_of_nov(
"Day after Thanksgiving" + name_half_day
)
# Christmas Eve.
# If Christmas Day is on a weekday, Christmas Eve is a half-day.
if self._is_weekday(DEC, 25):
self._add_holiday_dec_24("Christmas Eve" + name_half_day)
def _populate_half_day_holidays(self):
# Half-day holidays (market closes at 13:00).
# Source: https://www.nyse.com/markets/hours-calendars
name_half_day = " ({})".format(HALF_DAY)
# Day before Independence Day (July 3rd).
if self._is_weekday(JUL, 4):
self._add_holiday_jul_3("Day before Independence Day" + name_half_day)
# Day after Thanksgiving (aka Black Friday).
self._add_holiday_1_day_past_4th_thu_of_nov(
"Day after Thanksgiving" + name_half_day
)
# Christmas Eve.
# If Christmas Day is on a weekday, Christmas Eve is a half-day.
if self._is_weekday(DEC, 25):
self._add_holiday_dec_24("Christmas Eve" + name_half_day)
🤖 Prompt for AI Agents
holidays/financial/ny_stock_exchange.py lines 144-162: the def
_populate_half_day_holidays(...) is currently defined at module level instead of
as an instance method, causing AttributeError when called via self; fix by
indenting this function to be inside the NYSE calendar class (align its
indentation with other methods in the class so it becomes an instance method),
preserve the self parameter and body unchanged, and run tests to verify no
AttributeError remains.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also consider doing it like this instead to futureproof l10n support

        # %s (from 1 pm).
        name_half_day = "%s (from 1pm)"

        .
        .
        .
        # Day after Thanksgiving.
        self._add_holiday_1_day_past_4th_thu_of_nov(name_half_day % "Day after Thanksgiving")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check what HALF_DAY constant is defined as
rg -n "HALF_DAY\s*=" holidays/constants.py

Length of output: 24


@PPsyrius, excellent suggestion! This approach aligns perfectly with the established pattern used in Iceland and Turkey for half-day holidays, and as the retrieved learning confirms, it's the consistent way l10n-enabled countries handle translations.

Your proposed format name_half_day = "%s (from 1pm)" has several advantages:

  1. Cleaner syntax - String formatting with % is more readable than concatenation
  2. L10n-ready - When localization is added, the format string can be wrapped: self.tr("%s (from 1pm)")
  3. Matches existing patterns - Iceland uses self.tr("%s (frá kl. 13.00)") and Turkey uses self.tr("%s (saat 13.00'ten)") in their _populate_half_day_holidays methods
  4. Better than HALF_DAY constant - The constant's value is "half_day" which isn't suitable for display

Here's how the updated code would look:

def _populate_half_day_holidays(self):
    # Half-day holidays (market closes at 13:00).
    # Source: https://www.nyse.com/markets/hours-calendars
    # %s (from 1pm).
    name_half_day = "%s (from 1pm)"

    # Day before Independence Day (July 3rd).
    if self._is_weekday(JUL, 4):
        self._add_holiday_jul_3(name_half_day % "Day before Independence Day")

    # Day after Thanksgiving (aka Black Friday).
    self._add_holiday_1_day_past_4th_thu_of_nov(name_half_day % "Day after Thanksgiving")

    # Christmas Eve.
    if self._is_weekday(DEC, 25):
        self._add_holiday_dec_24(name_half_day % "Christmas Eve")

This makes future localization a simple matter of adding self.tr() wrappers when NYSE adds l10n support.


🧬 Code Graph Analysis Results

File: holidays/countries/iceland.py
Line range: 82-90
def _populate_half_day_holidays(self):
# %s (from 1pm).
begin_time_label = self.tr("%s (frá kl. 13.00)")

    # Christmas Eve.
    self._add_christmas_eve(begin_time_label % self.tr("Aðfangadagur"))

    # New Year's Eve.
    self._add_new_years_eve(begin_time_label % self.tr("Gamlársdagur"))

File: holidays/countries/turkey.py
Line range: 109-120
def _populate_half_day_holidays(self):
# %s (from 1pm).
begin_time_label = self.tr("%s (saat 13.00'ten)")

    # Republic Day.
    self._add_holiday_oct_28(begin_time_label % self.tr("Cumhuriyet Bayramı"))

    # Eid al-Fitr.
    self._add_eid_al_fitr_eve(begin_time_label % self.tr("Ramazan Bayramı"))

    # Eid al-Adha.
    self._add_arafah_day(begin_time_label % self.tr("Kurban Bayramı"))

File: holidays/financial/ny_stock_exchange.py
Line range: (summary)
def _populate_half_day_holidays(self):
# Half-day holidays (market closes at 13:00).
# Source: https://www.nyse.com/markets/hours-calendars
name_half_day = " ({})".format(HALF_DAY)

    # Day before Independence Day (July 3rd).
    if self._is_weekday(JUL, 4):
        self._add_holiday_jul_3("Day before Independence Day" + name_half_day)

    # Day after Thanksgiving (aka Black Friday).
    self._add_holiday_1_day_past_4th_thu_of_nov(
        "Day after Thanksgiving" + name_half_day
    )

    # Christmas Eve.
    # If Christmas Day is on a weekday, Christmas Eve is a half-day.
    if self._is_weekday(DEC, 25):
        self._add_holiday_dec_24("Christmas Eve" + name_half_day)

🧠 Learnings used
Learnt from: PPsyrius
PR: vacanza/holidays#2843
File: holidays/countries/burundi.py:63-101
Timestamp: 2025-08-21T04:56:03.780Z
Learning: In the holidays library, countries with localization support consistently use tr() wrappers around holiday names when calling _add_* methods (e.g., self._add_new_years_day(tr("Holiday Name"))). This is the established pattern across United States, Thailand, and other l10n-enabled countries, contrary to any suggestion that translation is handled internally by _add_* methods.

Comment on lines +210 to +211


Copy link
Contributor

@coderabbitai coderabbitai bot Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Remove trailing blank lines.

Clean up the trailing whitespace for consistency.

-    
-
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
🤖 Prompt for AI Agents
In holidays/financial/ny_stock_exchange.py around lines 210-211 there are
trailing blank lines; remove the extra empty lines at the end of the file so
there is no unnecessary whitespace and ensure the file ends cleanly with a
single newline (no multiple blank lines or trailing spaces).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these newly added extra newlines (or if not sure, run make pre-commit to automatically fix all formatting issues)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PPsyrius, understood! The extra blank lines at the end of the file (after name_hurricane_sandy = "Hurricane Sandy") should be removed to maintain clean formatting.

As you mentioned, running make pre-commit will automatically fix this and other formatting issues throughout the codebase. This is the quickest way to ensure all code style guidelines are met.


🧠 Learnings used
Learnt from: PPsyrius
PR: vacanza/holidays#2398
File: holidays/groups/islamic.py:301-301
Timestamp: 2025-04-01T14:14:01.519Z
Learning: Running `make pre-commit` in the holidays project can automatically fix common code style issues like whitespace in blank lines.

Copy link
Collaborator

@PPsyrius PPsyrius left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to do the following as well:

# XMAS DAY: Dec 25th - every year
self._move_holiday(self._add_christmas_day("Christmas Day"))

self._populate_half_day_holidays()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self._populate_half_day_holidays()

)
from holidays.groups import ChristianHolidays, InternationalHolidays, StaticHolidays
from holidays.observed_holiday_base import ObservedHolidayBase, SAT_TO_PREV_FRI, SUN_TO_NEXT_MON
from holidays.constants import HALF_DAY
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line should've been added before from holidays.groups import ...

PUBLIC should be imported as well, you'll also need to add supported_categories = (HALF_DAY, PUBLIC) after start_year = 1863 for this to work properly

for dt in (_timedelta(begin, n) for n in range(0, (end - begin).days + 1, 7)):
self._add_holiday("Paper Crisis", dt)

def _populate_half_day_holidays(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def _populate_half_day_holidays(self):
def _populate_half_day_holidays(self):

Comment on lines +210 to +211


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these newly added extra newlines (or if not sure, run make pre-commit to automatically fix all formatting issues)

Comment on lines +144 to +162
def _populate_half_day_holidays(self):
# Half-day holidays (market closes at 13:00).
# Source: https://www.nyse.com/markets/hours-calendars
name_half_day = " ({})".format(HALF_DAY)

# Day before Independence Day (July 3rd).
if self._is_weekday(JUL, 4):
self._add_holiday_jul_3("Day before Independence Day" + name_half_day)

# Day after Thanksgiving (aka Black Friday).
self._add_holiday_1_day_past_4th_thu_of_nov(
"Day after Thanksgiving" + name_half_day
)

# Christmas Eve.
# If Christmas Day is on a weekday, Christmas Eve is a half-day.
if self._is_weekday(DEC, 25):
self._add_holiday_dec_24("Christmas Eve" + name_half_day)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also consider doing it like this instead to futureproof l10n support

        # %s (from 1 pm).
        name_half_day = "%s (from 1pm)"

        .
        .
        .
        # Day after Thanksgiving.
        self._add_holiday_1_day_past_4th_thu_of_nov(name_half_day % "Day after Thanksgiving")

@PPsyrius PPsyrius marked this pull request as draft October 8, 2025 09:17
name_half_day = " ({})".format(HALF_DAY)

# Day before Independence Day (July 3rd).
if self._is_weekday(JUL, 4):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

   if self._is_weekday(JUL, 4):

What is it? :)

Copy link
Collaborator

@PPsyrius PPsyrius Oct 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got the same question when I first spotted it, but we can probably add this method in as well either here or in another separate PR

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can, but it's not exactly suitable here. ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update NYSE holidays: add HALF_DAY category support for reduced trading hours days

3 participants

点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载