Rework RecurrenceId to use date/datetime and range - #513
Conversation
|
Thank you for making this contribution. Can you update the PR description with a description of the rules, whats changing, and how it fixes any issues with implementing the RFC? (any other caveats, issues not fixed, etc) Thank you. |
|
Sure, should be updated now. |
|
Thanks for updating the description. I think there is more needed to make this work. Namely, the tests are not passing, so its breaking the API in some ways. This needs to be compatible with existing APIs or it will be a breaking change. If we want to do a breaking change then we need to actually fix the full issues with how recurring event edits are handled. I think it needs to be compatible for now. |
|
Yeah, I just did this as a proof of concept to get feedback so I haven't updated the tests or other parts of the library, they are broken right now. I'm not sure if it's possible to correct this without a breaking change though, even just changing the value's type from a string into a date/datetime would break anything currently passing in a string. If you're fine with this direction and with making a breaking change release, I can finish this and implement the correct behavior for recurring events. If you'd like to prioritize compatibility instead, what would like me to do to make that happen? |
|
The major problem that needs to be fixed is the |
Handle props that are passed in as date, datetime.
Missed a test case where prop is an instance of RecurrenceId
Fix iterating over a recurrence.
|
This has now been updated to work with existing tests. It looks like stutrek did a lot of work earlier to do One question, my original draft had the boolean for |
# Conflicts: # uv.lock
|
Thanks for working on this! I did a detailed review of the proposed changes in this PR and wanted to share some key findings and concerns regarding matching, backwards compatibility, and the RFC 5545 spec: 1. Wall-Clock Time Mutation (Timezone Matching Bug)In the matching and conversion logic (e.g., in if timezone is not None:
if isinstance(date, datetime.datetime):
date = date.astimezone(timezone)If the input is a naive datetime representing the local start time of a recurrence instance (e.g., 2. Breaking API ChangesChanging
3. Inline Parameter ParsingThe PR's 4. RFC 5545 ConformanceTo fully satisfy Section 3.8.4.4 of RFC 5545:
|
|
Thank you again for this contribution — I want to give proper credit here because this PR did a lot of the hard thinking that shaped where we ended up. Your analysis of RFC 5545 §3.8.4.4 was spot-on, and the core design decisions in this PR — surfacing Where I hesitated to merge was primarily around backward compatibility: changing What we did in #628 (just merged) is essentially Phase 1 built on your groundwork: we kept The Phase 2 work — plumbing |
This is my suggestion for improving recurrence-id serializing/parsing #278. It now works with dates and supports RANGE as well (although it doesn't enumerate correctly yet in
timespan).A number of tests still need to be updated, some are just the snapshots but others should probably get this functionality confirmed before we change them.
Thank you for this library!
https://datatracker.ietf.org/doc/html/rfc5545#autoid-93
In short, the RFC states that Recurrence ID has a value of type
DATEorDATE-TIME(same value type as the event'sdtstart/dtend). ThisDATE/DATE-TIMEmust match an instance of the event within the recurrence, and it will override that one. Recurrence ID also has a few optional parameters:VALUEwhich can explicitly state whether it isDATEorDATE-TIME, the TZID timezone (similar to otherDATE-TIMEproperties), andRANGE, which only has one valid value,THISANDFUTURE, and signals this override should also apply to all additional following instances of the event.Here's an example giving all optional parameters
Prior to this PR,
RecurrenceIdcould not set the parameters, only the value, and the input type was a string instead of date/datetime. While one could potentially format at least the date value correctly on their own, there was no way to set the timezone for that date or enableTHISANDFUTURErange. Anecdotally, this caused a lot of confusion for me using the library about what sort of value I needed to provide, and was an issue because my use case depends on Recurrence ID heavily.This PR reworks
RecurrenceIdinto a Pydantic model with two fields:datewhich accepts either adateordatetimeobject, andthis_and_future, which is a boolean and addsRANGE=THISANDFUTUREto the params. The model now both parses and encodes these as well.This was proposed to get an idea of whether this was the right way to implement it, but it's incomplete and requires some additional changes:
RecurrenceIdcorrectly, particularly ontimespanTHISANDFUTURErangeRecurrenceId's type matchesdtstarton the eventRecurrenceId's date matches a time given by the recurrence rule.rruleandrecurrence-idare not both populated on the same event. (Saw an offhand comment about this but need stronger confirmation from the spec this is necessary)