+
Skip to content

Conversation

jntdst
Copy link

@jntdst jntdst commented Sep 3, 2025

Proposed change
This PR addresses and fixes a one-day discrepancy for estimated Islamic (lunar) holidays in Iran.

Currently, future lunar holidays calculated by the library for Iran are consistently off by one day compared to the official Iranian calendar. For example, an event officially on a Tuesday is often incorrectly listed as Monday (estimated). This causes reliability issues for users planning based on future dates.

This change implements a structural fix directly within the Iran class in holidays/countries/iran.py:

The _add_islamic_calendar_holiday method is overridden: This method now intercepts Islamic holidays before they are added.

Automatic Date Correction: If a holiday is flagged as is_estimated, the method automatically adds timedelta(days=1) to its date, aligning it with the official calendar.

Removal of "(estimated)" Label: The islamic_show_estimated flag is now forced to False in the class constructor. Since the dates are corrected, displaying the "estimated" label is no longer necessary and would be confusing.

This approach provides a permanent and transparent solution, ensuring that all future holiday calculations for Iran are accurate without requiring any post-processing by the end-user.

Type of change
[ ] New country/market holidays support (thank you!)

[x] 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
[* ] I've read and followed the contributing guidelines.

[* ] I've run make check locally; all checks and tests passed.

Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
Signed-off-by: jntdst <jntdst@gmail.com>
fix(holidays): Correct one-day offset for estimated Iranian holidays

Signed-off-by: jntdst <jntdst@gmail.com>
Copy link
Contributor

coderabbitai bot commented Sep 3, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Adjusted certain Iranian Islamic holiday dates by one day to correct previously estimated entries.
  • Refactor

    • Removed the user-facing option to toggle estimated Islamic holiday handling; behavior is now consistent and automatic.
  • Documentation

    • Updated guidance to reflect the removal of the estimated-date toggle and the new automatic handling of date corrections.

Walkthrough

Constructor of Iran class now accepts variadic args/kwargs and removes islamic_show_estimated handling. Imports updated. A private override adjusts estimated Islamic holiday dates by +1 day before delegating to the parent method. Documentation updated accordingly. Public holiday population flow otherwise unchanged.

Changes

Cohort / File(s) Summary
Iran holidays implementation
`holidays/countries/iran.py`
- Changed Iran.init to `def init(self, *args, **kwargs)` and strips any `islamic_show_estimated` from kwargs.
- Hard-codes `show_estimated=False` when initializing Islamic holidays.
- Added private method to apply +1 day correction to dates flagged as estimated before calling parent _add_islamic_calendar_holiday.
- Added imports: `date`, `timedelta`, `Iterable`.
Docs update
`docs/...`
Updated docs to remove `islamic_show_estimated` parameter and describe internal date-correction behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

l10n

Suggested reviewers

  • arkid15r
  • KJhellico
  • PPsyrius

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 20d9bc3 and 6bcbd02.

📒 Files selected for processing (1)
  • holidays/countries/iran.py (2 hunks)
🧰 Additional context used
🧠 Learnings (18)
📓 Common learnings
Learnt from: KJhellico
PR: vacanza/holidays#2850
File: holidays/countries/christmas_island.py:75-80
Timestamp: 2025-08-22T19:06:04.303Z
Learning: Christmas Island's docstring for the `islamic_show_estimated` parameter follows the exact same format used consistently across all countries with Islamic holidays in the codebase: "Whether to add 'estimated' label to Islamic holidays name if holiday date is estimated." This is the standard, established pattern and should not be changed.
Learnt from: PPsyrius
PR: vacanza/holidays#2614
File: holidays/countries/guyana.py:78-90
Timestamp: 2025-06-13T12:18:03.539Z
Learning: The holidays codebase now uses the constructor signature pattern `__init__(self, *args, islamic_show_estimated: bool = True, **kwargs)` across country classes.
Learnt from: KJhellico
PR: vacanza/holidays#2706
File: holidays/countries/cayman_islands.py:50-55
Timestamp: 2025-07-10T15:55:34.523Z
Learning: The `islamic_show_estimated` parameter in country class constructors is only needed for countries that implement Islamic holidays (inherit from IslamicHolidays or _CustomIslamicHolidays groups). Countries with only Christian and secular holidays do not need this parameter.
Learnt from: PPsyrius
PR: vacanza/holidays#2848
File: tests/countries/test_somalia.py:44-127
Timestamp: 2025-08-25T04:28:02.061Z
Learning: In the holidays library, Islamic holiday tests use `self.no_estimated_holidays = Country(years=years, islamic_show_estimated=False)` as the library-wide standard approach to simplify test cases. This pattern is intentional and preferred over testing estimated labels.
Learnt from: Wasif-Shahzad
PR: vacanza/holidays#2593
File: holidays/calendars/islamic.py:3993-3994
Timestamp: 2025-06-04T10:09:28.732Z
Learning: In the holidays/calendars/islamic.py file, the Islamic calendar date methods in the _IslamicLunar class (like ali_al_rida_death_dates, ashura_dates, etc.) follow a consistent pattern of being single-line methods that return self._get_holiday(CONSTANT, year) without docstrings. New methods should follow this same pattern for consistency.
Learnt from: KJhellico
PR: vacanza/holidays#2388
File: holidays/countries/ivory_coast.py:127-128
Timestamp: 2025-03-30T18:22:11.939Z
Learning: The IvoryCoast class in holidays/countries/ivory_coast.py already includes documentation in its class docstring explaining the "day after" naming convention for Islamic holidays, noting that in the Islamic calendar, days begin at sunset and the "day after" refers to daylight hours following the night of celebration.
Learnt from: KJhellico
PR: vacanza/holidays#2465
File: holidays/countries/suriname.py:219-251
Timestamp: 2025-04-13T19:10:31.502Z
Learning: The `_CustomIslamicHolidays` classes in this project contain only exact verified holiday dates from reliable sources, rather than calculated or estimated future dates. This is by design to ensure accuracy, particularly for religious holidays that may follow lunar calendars or depend on local observations.
Learnt from: PPsyrius
PR: vacanza/holidays#2632
File: holidays/countries/solomon_islands.py:95-98
Timestamp: 2025-06-16T12:28:31.641Z
Learning: Library-wide holiday patterns and their optimizations should be handled at the base class level (like InternationalHolidays) rather than documenting workarounds in individual country modules. This maintains separation of concerns and avoids documentation duplication.
Learnt from: KJhellico
PR: vacanza/holidays#2831
File: holidays/countries/south_sudan.py:84-88
Timestamp: 2025-08-19T21:00:47.849Z
Learning: In the holidays library, Islamic holidays use dedicated methods for additional days (like `_add_eid_al_fitr_day_two`, `_add_eid_al_adha_day_two`) rather than parameters. The methods don't accept a `days` parameter - each day has its own specific method.
Learnt from: PPsyrius
PR: vacanza/holidays#2643
File: holidays/countries/mauritius.py:144-169
Timestamp: 2025-06-19T02:34:18.382Z
Learning: Custom holiday classes that extend _CustomHinduHolidays, _CustomIslamicHolidays, _CustomBuddhistHolidays, etc. in the holidays library do not use docstrings. They follow a pattern of using only inline comments above date dictionaries, as seen in Malaysia, Singapore, UAE, and other country implementations.
📚 Learning: 2025-06-13T12:18:03.539Z
Learnt from: PPsyrius
PR: vacanza/holidays#2614
File: holidays/countries/guyana.py:78-90
Timestamp: 2025-06-13T12:18:03.539Z
Learning: The holidays codebase now uses the constructor signature pattern `__init__(self, *args, islamic_show_estimated: bool = True, **kwargs)` across country classes.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-07-10T15:55:34.523Z
Learnt from: KJhellico
PR: vacanza/holidays#2706
File: holidays/countries/cayman_islands.py:50-55
Timestamp: 2025-07-10T15:55:34.523Z
Learning: The `islamic_show_estimated` parameter in country class constructors is only needed for countries that implement Islamic holidays (inherit from IslamicHolidays or _CustomIslamicHolidays groups). Countries with only Christian and secular holidays do not need this parameter.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-08-22T19:06:04.303Z
Learnt from: KJhellico
PR: vacanza/holidays#2850
File: holidays/countries/christmas_island.py:75-80
Timestamp: 2025-08-22T19:06:04.303Z
Learning: Christmas Island's docstring for the `islamic_show_estimated` parameter follows the exact same format used consistently across all countries with Islamic holidays in the codebase: "Whether to add 'estimated' label to Islamic holidays name if holiday date is estimated." This is the standard, established pattern and should not be changed.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-08-25T04:28:02.061Z
Learnt from: PPsyrius
PR: vacanza/holidays#2848
File: tests/countries/test_somalia.py:44-127
Timestamp: 2025-08-25T04:28:02.061Z
Learning: In the holidays library, Islamic holiday tests use `self.no_estimated_holidays = Country(years=years, islamic_show_estimated=False)` as the library-wide standard approach to simplify test cases. This pattern is intentional and preferred over testing estimated labels.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-06-04T10:09:28.732Z
Learnt from: Wasif-Shahzad
PR: vacanza/holidays#2593
File: holidays/calendars/islamic.py:3993-3994
Timestamp: 2025-06-04T10:09:28.732Z
Learning: In the holidays/calendars/islamic.py file, the Islamic calendar date methods in the _IslamicLunar class (like ali_al_rida_death_dates, ashura_dates, etc.) follow a consistent pattern of being single-line methods that return self._get_holiday(CONSTANT, year) without docstrings. New methods should follow this same pattern for consistency.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-04-13T19:10:31.502Z
Learnt from: KJhellico
PR: vacanza/holidays#2465
File: holidays/countries/suriname.py:219-251
Timestamp: 2025-04-13T19:10:31.502Z
Learning: The `_CustomIslamicHolidays` classes in this project contain only exact verified holiday dates from reliable sources, rather than calculated or estimated future dates. This is by design to ensure accuracy, particularly for religious holidays that may follow lunar calendars or depend on local observations.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-03-30T08:08:30.415Z
Learnt from: PPsyrius
PR: vacanza/holidays#2388
File: holidays/countries/ivory_coast.py:84-85
Timestamp: 2025-03-30T08:08:30.415Z
Learning: Islamic holiday logic should be implemented in the holidays/groups/islamic.py file, with country-specific files only calling these methods with the appropriate translated names.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-03-30T18:22:11.939Z
Learnt from: KJhellico
PR: vacanza/holidays#2388
File: holidays/countries/ivory_coast.py:127-128
Timestamp: 2025-03-30T18:22:11.939Z
Learning: The IvoryCoast class in holidays/countries/ivory_coast.py already includes documentation in its class docstring explaining the "day after" naming convention for Islamic holidays, noting that in the Islamic calendar, days begin at sunset and the "day after" refers to daylight hours following the night of celebration.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-08-21T04:56:03.780Z
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.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-06-19T02:34:14.456Z
Learnt from: PPsyrius
PR: vacanza/holidays#2643
File: holidays/countries/mauritius.py:171-184
Timestamp: 2025-06-19T02:34:14.456Z
Learning: In the holidays library, `_CustomIslamicHolidays` subclasses follow a consistent pattern of NOT having docstrings. They go directly to defining date dictionaries, as evidenced by Malaysia, Singapore, UAE, and dozens of other country implementations.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-08-21T05:56:33.276Z
Learnt from: PPsyrius
PR: vacanza/holidays#2843
File: holidays/countries/burundi.py:15-16
Timestamp: 2025-08-21T05:56:33.276Z
Learning: In the holidays library, when importing Gregorian month constants from holidays.calendars.gregorian, only import the months that are actually used in the date data. For example, if Islamic holiday dates only reference JUN, JUL, SEP, OCT, then only import those specific constants rather than importing additional unused months.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-06-19T02:34:18.382Z
Learnt from: PPsyrius
PR: vacanza/holidays#2643
File: holidays/countries/mauritius.py:144-169
Timestamp: 2025-06-19T02:34:18.382Z
Learning: Custom holiday classes that extend _CustomHinduHolidays, _CustomIslamicHolidays, _CustomBuddhistHolidays, etc. in the holidays library do not use docstrings. They follow a pattern of using only inline comments above date dictionaries, as seen in Malaysia, Singapore, UAE, and other country implementations.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-08-21T04:56:03.780Z
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 DO use tr() wrappers around holiday names when calling _add_* methods. This is the correct pattern for l10n-enabled country implementations, contrary to previous learning about translation being handled internally by _add_* methods.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-05-06T13:01:22.693Z
Learnt from: Wasif-Shahzad
PR: vacanza/holidays#2522
File: holidays/countries/yemen.py:158-163
Timestamp: 2025-05-06T13:01:22.693Z
Learning: In the holidays library, the RAMADAN_BEGINNING_DATES dictionary in country-specific Islamic holiday classes (like YemenIslamicHolidays) is used indirectly through the backend. When a country class calls _add_holiday_29_ramadan(), the IslamicHolidays implementation uses the country's custom calendar dates to calculate the 29th day of Ramadan by adding 28 days to the beginning date.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-08-26T21:24:41.827Z
Learnt from: KJhellico
PR: vacanza/holidays#2860
File: holidays/countries/burkina_faso.py:27-30
Timestamp: 2025-08-26T21:24:41.827Z
Learning: Countries in the holidays library that don't have localization support yet should use plain English strings for labels (e.g., `estimated_label = "%s (estimated)"`), while only countries with existing .po translation files should use `tr()` wrapping. Check for the presence of .po files in holidays/locale to determine if a country has localization support.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-06-16T14:08:09.492Z
Learnt from: KJhellico
PR: vacanza/holidays#2635
File: holidays/countries/bhutan.py:13-16
Timestamp: 2025-06-16T14:08:09.492Z
Learning: In the holidays library, translation is performed in the `_add_holiday` methods, not at the string level. Holiday strings passed to `_add_holiday_*` methods are processed through the translation machinery within those methods, so using `tr()` or `self.tr()` wrappers is unnecessary.

Applied to files:

  • holidays/countries/iran.py
📚 Learning: 2025-06-29T10:36:06.138Z
Learnt from: KJhellico
PR: vacanza/holidays#2671
File: holidays/countries/libya.py:51-108
Timestamp: 2025-06-29T10:36:06.138Z
Learning: There is no project-wide convention in the holidays library to organize holidays by calendar type (Islamic holidays first, then Gregorian holidays). Countries organize holidays in various ways - often chronologically, by importance, or by logical grouping - and Islamic holidays are frequently placed at the end of the _populate_public_holidays method rather than at the beginning.

Applied to files:

  • holidays/countries/iran.py
🧬 Code graph analysis (1)
holidays/countries/iran.py (2)
holidays/groups/islamic.py (2)
  • IslamicHolidays (20-443)
  • _add_islamic_calendar_holiday (265-281)
holidays/groups/persian.py (1)
  • PersianCalendarHolidays (20-169)
🔇 Additional comments (3)
holidays/countries/iran.py (3)

13-14: Imports look fine.

Typing via collections.abc and timedelta usage are appropriate for the override.


55-68: The grep didn’t surface any internal calls to Iran(…) passing islamic_show_estimated, so we can’t be sure nothing outside this patch relies on the kwarg being dropped and forced to False. Please manually audit any callers (including tests and user code) to confirm it’s safe to restore the standard signature before making that change.


72-89: Guard None dates and avoid building an intermediate list.

If any provider yields (None, is_estimated), the current code will raise on timedelta. Use a generator and skip None.

-        corrected_dates = []
-        for dt, is_estimated in dates:
-            if is_estimated:
-                # Add one day to estimated dates to correct them.
-                corrected_dates.append((dt + timedelta(days=1), is_estimated))
-            else:
-                corrected_dates.append((dt, is_estimated))
-
-        # Call the parent method with the corrected dates.
-        return super()._add_islamic_calendar_holiday(name, corrected_dates, days_delta)
+        one_day = timedelta(days=1)
+        corrected_dates = (
+            ((dt + one_day) if is_estimated else dt, is_estimated)
+            for (dt, is_estimated) in dates
+            if dt is not None
+        )
+        return super()._add_islamic_calendar_holiday(name, corrected_dates, days_delta)
⛔ Skipped due to learnings
Learnt from: PPsyrius
PR: vacanza/holidays#2848
File: tests/countries/test_somalia.py:44-127
Timestamp: 2025-08-25T04:28:02.061Z
Learning: In the holidays library, Islamic holiday tests use `self.no_estimated_holidays = Country(years=years, islamic_show_estimated=False)` as the library-wide standard approach to simplify test cases. This pattern is intentional and preferred over testing estimated labels.
Learnt from: KJhellico
PR: vacanza/holidays#2831
File: holidays/countries/south_sudan.py:84-88
Timestamp: 2025-08-19T21:00:47.849Z
Learning: In the holidays library, Islamic holidays use dedicated methods for additional days (like `_add_eid_al_fitr_day_two`, `_add_eid_al_adha_day_two`) rather than parameters. The methods don't accept a `days` parameter - each day has its own specific method.
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • 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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

sonarqubecloud bot commented Sep 3, 2025

Comment on lines -54 to +59
def __init__(self, *args, islamic_show_estimated: bool = True, **kwargs):
def __init__(self, *args, **kwargs):
"""
Args:
islamic_show_estimated:
Whether to add "estimated" label to Islamic holidays name
if holiday date is estimated.
Initializes the Iran holidays class.
The `islamic_show_estimated` parameter is removed and forced to False
to handle date corrections internally.
Copy link
Collaborator

Choose a reason for hiding this comment

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

No need to remove this parameter, False as default value is enough.

for dt, is_estimated in dates:
if is_estimated:
# Add one day to estimated dates to correct them.
corrected_dates.append((dt + timedelta(days=1), is_estimated))
Copy link
Collaborator

Choose a reason for hiding this comment

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

We have _timedelta function in holidays.calendars.gregorian for that.

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.

2 participants

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