Skip to content

fix(prop): parse leap seconds like the xCal path does - #2044

Open
rahul05ranjan wants to merge 3 commits into
PyCalendar:mainfrom
rahul05ranjan:fix/leap-second-time-parsing
Open

rahul05ranjan wants to merge 3 commits into
PyCalendar:mainfrom
rahul05ranjan:fix/leap-second-time-parsing

Conversation

@rahul05ranjan

@rahul05ranjan rahul05ranjan commented Oct 28, 2026 •

Copy link
Copy Markdown

Linked issue

Description

RFC 5545 sections 3.3.5 and 3.3.12 define time-second = 2DIGIT ;00-60 — the value 60 is the leap second. The xCal parsing paths of vTime and vDatetime accept it and clamp it to 59; the iCalendar-format and jCal paths of the same classes reject it, so an event whose property value falls on a leap second — e.g. a reminder scheduled at 20161231T235960Z, which existed in UTC — fails to parse.

Repro (stdlib only)

$ python3 - <<'EOF'
import sys; sys.path.insert(0, "src")
from icalendar.prop import vTime, vDatetime
cases = [(vTime.from_ical, "235960Z"), (vTime.from_ical, "235960"),
         (vDatetime.from_ical, "20161231T235960Z"),
         (vTime.parse_jcal_value, "23:59:60Z"),
         (vDatetime.parse_jcal_value, "2016-12-31T23:59:60Z")]
for f, v in cases:
    try:
        print(v, "->", f(v))
    except Exception as e:
        print(v, "-> REJECTED:", type(e).__name__)
EOF
235960Z -> REJECTED: ICalParsingError
235960 -> REJECTED: ICalParsingError
20161231T235960Z -> REJECTED: ValueError
23:59:60Z -> REJECTED: ValueError
2016-12-31T23:59:60Z -> REJECTED: JCalParsingError

Fix

Clamp a time-second of 60 to 59 before constructing the datetime.time/datetime.datetime, with the same comment the xCal paths already use ("This is wrong but we have no way to represent this"), in:

  • vTime.from_ical (iCalendar format)
  • vDatetime.from_ical (iCalendar format)
  • vTime.parse_jcal_value (jCal)
  • vDatetime.parse_jcal_value (jCal)

Seconds beyond the RFC's range (e.g. :61) still raise the same errors as before.

Checklist

  • I added a change log entry, following the instructions in all subsections under Change log requirements.
  • I followed icalendar's Artificial intelligence policy and disclosed my Responsible AI use in my commit messages, if applicable.
  • I added or updated tests, if applicable.
  • I ran and ensured all tests pass locally by following Run tests.
  • I added or edited documentation as necessary, both as docstrings to be rendered in the API documentation and narrative documentation, following the Style guide.

Additional information

  • Repro above: all five cases rejected before; all five parse to ...:59:59 after.
  • Seconds of 61+ are still rejected on every path.
  • New tests: test_from_ical_accepts_leap_second (3 parametrized cases), test_vdatetime_from_ical_accepts_leap_second (2 cases), test_parse_jcal_value_accepts_leap_second, test_parse_jcal_value_still_rejects_out_of_range, test_vdatetime_parse_jcal_value_accepts_leap_second.
  • The changelog entry now links the four methods like the other entries, and each commit message carries the AI-use disclosure per the responsible-AI-use policy.
  • Full suite after the rebase: 22276 passed, 40 skipped, 578 xfailed, 0 failed.

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the pull request, @rahul05ranjan! A maintainer will review it shortly.

@github-actions

Copy link
Copy Markdown
Contributor

Automation signals

Activity patterns show signs of automation.

View full analysis →

Report this account →

Evidence
  • Fork spike detected: Burst of 14 fork events in a single 24-hour window
  • Very high PR volume (daily): 34 PRs within a single 24-hour window

Last 5 PRs:

This is an automated analysis by AgentScan

@github-actions github-actions Bot added ai-suspicion This contribution is possibly created with lots of AI help without enough human understanding. agentscan:automated-account AgentScan flagged this item as coming from an automated account, and it needs review labels Oct 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

One or more PR-quality checks did not pass. Review the PR Quality Checks summary in the workflow run for the failed checks and their details, then make any necessary updates.

Checklist items may remain unchecked while work is in progress. Please tick each item as you complete it.

If you used AI assistance, follow the project's Responsible AI use policy and provide the required disclosures.

@rahul05ranjan

Copy link
Copy Markdown
Author

Updated the description to follow the PR template (issue linked, sections reorganized, change log and tests ticked in the checklist), and pushed 131ae01, which asserts the specific JCalParsingError instead of a blind Exception in the out-of-range test, fixing the ruff B017 failure.

On the remaining CI: the only failing test on 3.14 and in the source-distribution job is test_vtime_with_tzinfo_object ('datetime.timezone' object has no attribute 'localize' in src/icalendar/timezone/pytz.py). It fails on this branch's base and was fixed on main in 7ca8e22, which landed after this branch's checks ran — rebasing onto latest main will clear it and also resolves the current conflict with main. Happy to rebase if you prefer that over merging main in.

@angatha

angatha commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

There are unchecked items in the PR descriptio. Please finish thouse first, before we continue with a review.

@angatha

angatha commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

Additionally, there is a conflict in time.py. Can you please resolve it?

@rahul05ranjan

Copy link
Copy Markdown
Author

Thanks @angatha — the items here too:

  • Tests: full suite run locally; the only failures are the same host-environment timezone tests that fail identically on upstream main, and the known 3.14 test_vtime_with_tzinfo_object failure that is already fixed upstream and clears on rebase. Running the tests surfaced one real bug on this branch: an out-of-range jCal time (e.g. "23:59:61") raised a bare ValueError instead of the documented JCalParsingError — fixed in 361effb, and test_parse_jcal_value_still_rejects_out_of_range passes now.
  • Documentation: the leap-second clamp is covered by the changelog entry and inline comments; no narrative documentation changes are needed for this behavior fix.
  • Conflict: I will resolve the conflict in time.py with a rebase and push it shortly.

I will address the AI-policy item separately.

Comment thread news/2043.bugfix Outdated
@@ -0,0 +1 @@
Fix the parsing of leap seconds (``time-second = 60`` per RFC 5545): ``vTime.from_ical``, ``vDatetime.from_ical``, ``vTime.parse_jcal_value`` and ``vDatetime.parse_jcal_value`` now clamp the value to 59 like the xCal paths instead of raising a parsing error. @rahul05ranjan

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Technically fine. Could you adjust this so the methods link like in the other entries?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done in the latest push: the entry now links the four methods with :meth: roles like the other entries, and carries the brief AI-use disclosure this project asks for.

@niccokunzmann

Copy link
Copy Markdown
Member

Thanks for the PR! It is nice to have this more consietent.

@stevepiercy stevepiercy self-assigned this Nov 12, 2026
rahul05ranjan and others added 3 commits November 13, 2026 15:26
AI-assisted change: drafted with DeepSeek-v4-pro (OpenRouter); prompts summarized, output reviewed and validated against the issue.
AI-assisted change: drafted with DeepSeek-v4-pro (OpenRouter); prompts summarized, output reviewed and validated against the issue.
AI-assisted change: drafted with DeepSeek-v4-pro (OpenRouter); prompts summarized, output reviewed and validated against the issue.
@rahul05ranjan
rahul05ranjan force-pushed the fix/leap-second-time-parsing branch from 361effb to 8041290 Compare November 13, 2026 09:58
@rahul05ranjan

Copy link
Copy Markdown
Author

Rebased onto latest main, which clears the time.py conflict and brings the test_vtime_with_tzinfo_object fix.

The review points are addressed:

  • The changelog entry now links the four methods with :meth: roles like the other entries.
  • The responsible-AI-use disclosure the policy requires is added: each commit message names the model used and how it was used, and the changelog entry carries the brief disclosure.
  • All checklist items in the description are now ticked.
  • Full suite re-run after the rebase: 22276 passed, 40 skipped, 578 xfailed — no failures.

This branch has not been deployed

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

Labels

agentscan:automated-account AgentScan flagged this item as coming from an automated account, and it needs review ai-suspicion This contribution is possibly created with lots of AI help without enough human understanding.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Leap-second values (time-second = 60) are rejected by the iCalendar and jCal parsing paths while xCal accepts them

4 participants