-
-
Notifications
You must be signed in to change notification settings - Fork 17
Description
Hello!
First of all, thank you for rrule-temporal - I recently migrated from rrule and I really appreciate the move toward the Temporal API and the stricter spec handling.
I’m opening this issue mainly to better understand the RFC 5545 interpretation used in this library for UNTIL, and to ask whether alternative interpretations could also be considered in-spec. This is not meant as a complaint about the current behavior.
Context
After switching from rrule to rrule-temporal, I noticed that a recurrence string that previously parsed successfully no longer does.
The RRULE generated by the previous library is:
DTSTART;TZID=Europe/Berlin:20250601T043000
RRULE:FREQ=WEEKLY;UNTIL=20250615T000000;BYDAY=MO,WE,TH,SA,SU
(Until here is provided as local time in the same TZID as DTSTART, but would be able to be converted to UTC time)
The rrule library allowed to provide a RRuleDt object for both "since" and "until" and to specify the tzid separately, which is then encoded in the "DTSTART" part.
Key points:
- DTSTART is a DATE-TIME with local time and a TZID (Europe/Rome)
- UNTIL is a DATE-TIME without Z and without TZID
This was accepted by rrule, but rrule-temporal rejects it.
From looking at the source, I understand this is because rrule-temporal requires UNTIL to be UTC when DTSTART is specified with a TZID.
RFC 5545 §3.3.10 (Recurrence Rule) states:
The UNTIL rule part defines a DATE or DATE-TIME value that bounds
the recurrence rule in an inclusive manner. If the value
specified by UNTIL is synchronized with the specified recurrence,
this DATE or DATE-TIME becomes the last instance of the
recurrence. The value of the UNTIL rule part MUST have the same
value type as the "DTSTART" property. Furthermore, if the
"DTSTART" property is specified as a date with local time, then
the UNTIL rule part MUST also be specified as a date with local
time. If the "DTSTART" property is specified as a date with UTC
time or a date with local time and time zone reference, then the
UNTIL rule part MUST be specified as a date with UTC time. In the
case of the "STANDARD" and "DAYLIGHT" sub-components the UNTIL
rule part MUST always be specified as a date with UTC time. If
specified as a DATE-TIME value, then it MUST be specified in a UTC
time format. If not present, and the COUNT rule part is also not
present, the "RRULE" is considered to repeat forever.
I take this to mean that:
- The value of the UNTIL rule part MUST have the same value type as the "DTSTART" property, so either "date" or "date-time" as defined by sect 3.3.5.
- If DTSTART is a DATE-TIME with local time AND time zone reference (be it UTC or a different IANA timezone) then UNTIL must also be specified in UTC (with the Z designator for the Zulu timezone)
This makes the current implementation in the rrule-temporal library spec compliant as far as I understand, and the error I receive from this line to be completely justified.
Questions
I'm trying to better understand the intent behind this code path UNTIL
Specifically:
Validation order
Is there a reason the RFC validation is done after parsing?
Conceptually, a non-UTC UNTIL is first interpreted using the DTSTART TZID and only then rejected. Would pre-parse validation be more appropriate, or is this intentional?
DATE vs DATE-TIME
Is this UTC requirement enforced only for DATE-TIME UNTIL values, or also for DATE?
Does the behavior change when DTSTART itself is a DATE?
Floating UNTIL semantics
When DTSTART has a TZID and UNTIL is a DATE-TIME without Z or TZID, is the intermediate “local in DTSTART TZID” interpretation intentional, or just a side effect of parseIcsDateTime reuse?
Why not convert to UTC?
If UNTIL parses successfully as a Temporal.ZonedDateTime in the DTSTART TZID, is there a reason the library does not convert it to UTC instead of rejecting it?
Is the presence of "Z" treated as a hard syntactic requirement rather than a semantic one?
At this point, I’m satisfied that the current behavior is intentionally strict and spec-compliant, and that rejecting non-UTC UNTIL values when DTSTART has a TZID is by design rather than an oversight. I’ve adjusted the RRULE generation in my calendar to manually add the "Z" designator when UNTIL is a DATE-TIME, while I gradually migrate the generation logic to rrule-temporal as well.
I’m mainly interested in validating my understanding of the design choices and RFC interpretation, and I look forward to any discussion or clarification. Thanks in advance for your time and for maintaining the library.
Best regards,
Samuele