For an uncached DAILY rule, between() starts iteration at DTSTART and discards every occurrence through the lower bound. The example in #654 therefore replays roughly twenty years of daily occurrences to return one month.
Implementation
Let uncached between() queries request an iterator positioned near the lower bound.
For DAILY rules without COUNT, seek to the preceding aligned interval instead of replaying from DTSTART.
Preserve the existing path for cached rules, subclasses, incompatible timezone-awareness, floating timezone objects, datetime boundaries, and unsupported recurrence shapes.
Measured against current master on an AMD Ryzen 7 8845H under WSL2 with CPython 3.13.15. Each result is the median of 11 CPU-pinned timeit batches after 10 warm-up calls, using the reproducer from #654.
Version
Time per between() call
Current master
8.05 ms
This change
49.0 us
This is approximately a 164x speedup for #654's 20-year, uncached DAILY workload. Both versions return the same 30 occurrences; reaching the query interval requires 7,337 iterator pulls on master and 33 with this change.
The benefit scales with the distance from DTSTART: a query starting roughly one month after DTSTART improved from 76.5 us to 45.7 us (1.68x). A query that cannot use the seek path remained effectively unchanged (38.05 us on master and 38.20 us with this change). These measurements are specific to the supported DAILY seek path, not a general rrule-wide speedup claim.
CI compatibility
The branch keeps two current test-suite compatibility fixes as separate commits:
normalize the timezone property test to its UTC-aware Hypothesis input domain;
materialize isoparser parameters as required by pytest 9.1.
A 384-case differential matrix covering intervals, start hours, BYHOUR values, query distances, and inclusive/exclusive bounds had zero mismatches against the legacy path.
Key rrule, timezone-property, and isoparser tests passed on CPython 2.7, 3.7, 3.12 with pytest 9.1, and 3.14.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #654.
Supersedes #1557.
Problem
For an uncached DAILY rule, between() starts iteration at DTSTART and discards every occurrence through the lower bound. The example in #654 therefore replays roughly twenty years of daily occurrences to return one month.
Implementation
Performance
Measured against current master on an AMD Ryzen 7 8845H under WSL2 with CPython 3.13.15. Each result is the median of 11 CPU-pinned timeit batches after 10 warm-up calls, using the reproducer from #654.
This is approximately a 164x speedup for #654's 20-year, uncached DAILY workload. Both versions return the same 30 occurrences; reaching the query interval requires 7,337 iterator pulls on master and 33 with this change.
The benefit scales with the distance from DTSTART: a query starting roughly one month after DTSTART improved from 76.5 us to 45.7 us (1.68x). A query that cannot use the seek path remained effectively unchanged (38.05 us on master and 38.20 us with this change). These measurements are specific to the supported DAILY seek path, not a general rrule-wide speedup claim.
CI compatibility
The branch keeps two current test-suite compatibility fixes as separate commits:
Neither compatibility commit changes dateutil runtime behavior.
Validation
Disclosure
This change was developed with Codex assistance.