Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with event expansion #1478

Open
dozed opened this issue Apr 28, 2024 · 6 comments
Open

Issue with event expansion #1478

dozed opened this issue Apr 28, 2024 · 6 comments
Labels
dependency:dateutil external dependency "dateutil" related dependency:vobject external dependency "vobject" related not our bug issues which can't be fixed on server side

Comments

@dozed
Copy link

dozed commented Apr 28, 2024

_expand expects start and end as datetime which leads to an issue with dateutil's rruleset.between(start, end) with the following iCalendar event:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//foo//bar//EN
BEGIN:VEVENT
UID:fe1da58e-0555-11ef-9770-58ce2a14e2e5
DTSTART;VALUE=DATE:20240408
DTEND;VALUE=DATE:20240409
DTSTAMP:20240428T115356Z
RRULE:FREQ=WEEKLY;INTERVAL=1
SEQUENCE:1
SUMMARY:Test
END:VEVENT
END:VCALENDAR

Radicale logs this error:

[ERROR] An exception occurred during REPORT request on '/test/c59e3c20-4436-8258-9d21-ff25649c7290/': can't compare offset-naive and offset-aware datetimes

For a minimal test case see here: https://github.com/dozed/recur-issue-1/blob/main/test_recur_issue.py#L43-L55

The recurring-ical-events library seems to be able to handle mixed date/datetime values (example).

@dozed
Copy link
Author

dozed commented Apr 28, 2024

@pbiering pbiering added the dependency:vobject external dependency "vobject" related label Apr 28, 2024
@da4089
Copy link
Contributor

da4089 commented Apr 29, 2024

Thanks for the detailed report @dozed

@dozed
Copy link
Author

dozed commented Apr 29, 2024

One thing I forget to mention is that I wrote a small "hack" to fix another issue before:

Subject: [PATCH] Trying to fix event expansion
---
Index: radicale/app/report.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/radicale/app/report.py b/radicale/app/report.py
--- a/radicale/app/report.py	
+++ b/radicale/app/report.py	
@@ -243,17 +243,27 @@
     item = copy.copy(item)
     vevent = item.vobject_item.vevent
 
-    start_utc = vevent.dtstart.value.astimezone(datetime.timezone.utc)
-    vevent.dtstart = ContentLine(
-        name='DTSTART',
-        value=start_utc.strftime('%Y%m%dT%H%M%SZ'), params={})
+    if isinstance(vevent.dtstart.value, datetime.datetime):
+        start_utc = vevent.dtstart.value.astimezone(datetime.timezone.utc)
+        vevent.dtstart = ContentLine(
+            name='DTSTART',
+            value=start_utc.strftime('%Y%m%dT%H%M%SZ'), params={})
+    else:
+        vevent.dtstart = ContentLine(
+            name='DTSTART',
+            value=vevent.dtstart.value.strftime('%Y%m%d'), params={})
 
     dt_end = getattr(vevent, 'dtend', None)
     if dt_end is not None:
-        end_utc = dt_end.value.astimezone(datetime.timezone.utc)
-        vevent.dtend = ContentLine(
-            name='DTEND',
-            value=end_utc.strftime('%Y%m%dT%H%M%SZ'), params={})
+        if isinstance(dt_end.value, datetime.datetime):
+            end_utc = dt_end.astimezone(datetime.timezone.utc)
+            vevent.dtend = ContentLine(
+                name='DTEND',
+                value=end_utc.strftime('%Y%m%dT%H%M%SZ'), params={})
+        else:
+            vevent.dtend = ContentLine(
+                name='DTEND',
+                value=dt_end.value.strftime('%Y%m%d'), params={})
 
     timezones_to_remove = []
     for component in item.vobject_item.components():

@da4089
Copy link
Contributor

da4089 commented May 1, 2024

First off, in iCalendar 2.0, it's legal to use either a DATE type (with the VALUE=DATE property) or a DATE-TIME type for the DTSTART and DTEND fields. So this is a legitimate bug.

As @dozed points out, the problem occurs when dateutil 's rruleset.between() function gets a datetime.date instance as a parameter.

start_utc and end_utc get the value of vevent.dtstart and vevent.dtend: it's returned as datetime.date if they're dates. I think an argument could be made that they should be translated by vobject and returned as a datetime (not a date).

That does however open the issue of a timezone -- without one, we'd still hit the same issue comparing naive datetime with a timezoned datetime, but a workaround of just setting it to 00:00:00 UTC isn't correct, and (depending to the schedule) might actually cause errors if there's a recurrence early in the between() window (eg. 00:00 UTC is 10:00 Australia/Sydney, so a 9am Sydney event would not be returned, even though it's on the right date).

So I think this really should be fixed in dateutil, which should have special handling for date vs. datetime in between(), and do the right thing. Otherwise, using our own implementation of the between logic is probably the next best thing?

See https://github.com/dateutil/dateutil/blob/master/src/dateutil/rrule.py#L271-L302

Thoughts?

@pbiering pbiering added the dependency:dateutil external dependency "dateutil" related label May 1, 2024
@pbiering
Copy link
Collaborator

pbiering commented May 1, 2024

So I think this really should be fixed in dateutil, which should have special handling for date vs. datetime in between(), and do the right thing. Otherwise, using our own implementation of the between logic is probably the next best thing?

Would it be possible to create a "dateutil" version/feature depending code sniplet until it is fixed there?

If not fixed, one can't guess the version....can it be done by some kind of selftest during start....means as long as "dateutil" is not passing the selftest, use own implementation.

@pbiering
Copy link
Collaborator

which version of dateutil is currently used and can one try to use a newer one from here to check whether the issue is fixed meanwile: https://pypi.org/project/python-dateutil/#history

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dependency:dateutil external dependency "dateutil" related dependency:vobject external dependency "vobject" related not our bug issues which can't be fixed on server side
Projects
None yet
Development

No branches or pull requests

3 participants