Problem/Motivation

Follow-up to #3540328: Add “Raw RRULE” field and clarify COUNT field (“Raw RRULE string”). In that change, we allow reading an RRULE value mostly verbatim from storage. Some sources include EXDATE, RDATE, and/or EXRULE inline with the RRULE text. Per RFC 5545, these are separate iCalendar properties and must not be embedded within the RRULE property. As a result, VEVENTs produced today can contain a single RRULE string with embedded exclusions/inclusions that many consumers will ignore, causing exceptions and additional dates to be lost.

Steps to reproduce

  1. Create a Date iCal feed that uses the “Raw RRULE string” source (as added in #3540328).
  2. Populate the raw field with text that includes embedded exception/inclusion parts, for example:

    RRULE:FREQ=WEEKLY;BYDAY=MO,WE
    EXDATE=20251013T090000Z
    RDATE=20251027T090000Z
  3. Export the ICS and import it into a calendar client (Apple/Google/Outlook) or validate it.
  4. Observe that exclusions/inclusions may be ignored if they were left embedded within RRULE instead of emitted as their own properties.

Proposed resolution

  • Parse and split: When a “Raw RRULE string” is provided, parse the text for top-level property names within the VEVENT scope (RRULE, EXDATE, RDATE, optionally EXRULE).

D7 resolved it this way (thanks @ramil g for finding the lines)
https://git.drupalcode.org/project/date_ical/-/blob/7.x-3.x/date_ical.mo...
https://git.drupalcode.org/project/date_ical/-/blob/7.x-3.x/date_ical.ut...

Issue fork date_ical-3546087

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

joelpittet created an issue. See original summary.

ramil g made their first commit to this issue’s fork.

franceslui’s picture

I tested the patch from MR !10 and noticed problems in the generated .ics output. Specifically, EXDATE and RDATE are not separated from the RRULE block.

Example from the generated file:

RRULE:FREQ=WEEKLY;UNTIL=20251219T075959Z;INTERVAL=2;BYDAY=WE;WKST=Array

Here, WKST is incorrectly serialized as Array instead of SU.

Another example:

RRULE:FREQ=MONTHLY;UNTIL=20270502T065959Z;INTERVAL=1;BYDAY=WE;BYSETPOS=3 EXDATE:20240515T170000Z RDATE:20240514T070000Z;WKST=SU

In this case, EXDATE and RDATE are concatenated directly into the RRULE string instead of being emitted as separate EXDATE and RDATE properties.

The expected behavior is that RRULE, EXDATE, and RDATE each appear as independent iCalendar properties, e.g.:

RRULE:FREQ=WEEKLY;UNTIL=20251219T075959Z;INTERVAL=2;BYDAY=WE;WKST=SU
EXDATE:20240710T070000Z,20241113T080000Z,20241127T080000Z,20241211T080000Z
RDATE:20241106T080000Z,20241120T080000Z,20241204T080000Z,20241218T080000Z

Right now, the patch causes malformed .ics output where EXDATE/RDATE are embedded in RRULE, and WKST can degrade to Array. This makes the calendar invalid for many clients.

joelpittet’s picture

RE #4 @franceslui, I appreciate the details and I’m inclined to agree that WKST=Array may be related, but I didn’t see how you arrived at that conclusion from the comment. Could you share the steps you used to determine the linkage vs. WKST=Array being separate issues? For example, did you remove the EXDATE/RDATE content from the rrule column and retest to see whether WKST is output correct or something like that?

You also mentioned the current MR !10 doesn’t fix the problem. I agree: as it stands it appears to emit EXDATE/RDATE on their own lines, but it doesn’t remove those values from the RRULE line.

franceslui’s picture

RE #5 @joelpittet To determine the linkage between WKST=Array and the EXDATE/RDATE values not being split out of the raw RRULE string into separate VEVENT properties, I debugged the parseRruleString function in src/DateICal.php. When I called it with this input:

RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=WE;UNTIL=20251219T075959Z;WKST=SU EXDATE:20240710T070000Z,20241113T080000Z,20241127T080000Z,20241211T080000Z,20241225T080000Z,20250108T080000Z,20250122T080000Z RDATE:20241106T080000Z,20241120T080000Z,20241204T080000Z,20241218T080000Z,20250101T080000Z,20250115T080000Z

…it returned:

[
  'FREQ'     => 'WEEKLY',
  'INTERVAL' => 2,
  'BYDAY'    => 'WE',
  'UNTIL'    => '20251219T075959Z',
  'WKST'     => [
    'SU EXDATE:20240710T070000Z',
    '20241113T080000Z',
    '20241127T080000Z',
    '20241211T080000Z',
    '20241225T080000Z',
    '20250108T080000Z',
    '20250122T080000Z RDATE:20241106T080000Z',
    '20241120T080000Z',
    '20241204T080000Z',
    '20241218T080000Z',
    '20250101T080000Z',
    '20250115T080000Z',
  ],
]

This shows that because the code only splits on semicolons, everything after WKST=SU is lumped into the WKST value including the EXDATE and RDATE parts. That explains why WKST later gets serialized incorrectly as Array and why EXDATE/RDATE are embedded inside the RRULE rather than being emitted as separate VEVENT properties.

joelpittet’s picture

@franceslui RE #6 Ah, that is clearly related, it split on the comma separated EXDATE values as if they were part of the same set.

Thanks for the explanation about the semicolon split!

joelpittet’s picture

Status: Active » Needs work

  • joelpittet committed 5c06d1c1 on 4.x authored by ramil g
    [#3546087] feat: Split EXDATE/RDATE/EXRULE out of “Raw RRULE string”...
joelpittet’s picture

Status: Needs work » Fixed

Thanks again @ramil g and @franceslui for getting this sorted out. I will make a new release in a moment.

Now that this issue is closed, please review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, please credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.