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

[BUG] VTIMEZONE to_tz results in ValueError: RRULE UNTIL values must be specified in UTC when DTSTART is timezone-aware #708

Open
4 of 5 tasks
5ila5 opened this issue Sep 21, 2024 · 6 comments

Comments

@5ila5
Copy link

5ila5 commented Sep 21, 2024

Describe the bug

Getting timezone from a VTIMEZONE tag using to_tz() I get ValueError: RRULE UNTIL values must be specified in UTC when DTSTART is timezone-aware I noticed this while using icalevents but thought this might belong here and not to icalevents

I used the ICAL file: https://eilenburg.de/fileadmin/2024/Abfall_EG_1_Ost_2024.ics maybe they do not follow the spec but at least https://icalendar.org/validator.html did not report any issues

To Reproduce

import requests
import icalendar
from icalendar import Timezone

r = requests.get("https://eilenburg.de/fileadmin/2024/Abfall_EG_1_Ost_2024.ics")
r.encoding = "utf-8"
c = icalendar.Calendar.from_ical(r.text)
part: Timezone
for part in c.walk('VTIMEZONE'):
    print(isinstance(part, Timezone))
    tz = part.to_tz()
    print(tz)
...

Output:

True

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[1], line 13
     10 for part in c.walk('VTIMEZONE'):
     11     # print(event['SUMMARY'])
     12     print(isinstance(part, Timezone))
---> 13     tz = part.to_tz()
     14     print(tz)

File ~/Documents/coding/python/hacs_waste_collection_schedule/.venv/lib/python3.12/site-packages/icalendar/cal.py:653, in Timezone.to_tz(self)
    648         tzname = f"{zone}_{component['DTSTART'].to_ical().decode('utf-8')}_" + \
    649                  f"{component['TZOFFSETFROM'].to_ical()}_" + \
    650                  f"{component['TZOFFSETTO'].to_ical()}"
    651         tzname = self._make_unique_tzname(tzname, tznames)
--> 653     dst[tzname], component_transitions = self._extract_offsets(
    654         component, tzname
    655     )
    656     transitions.extend(component_transitions)
    658 transitions.sort()

File ~/Documents/coding/python/hacs_waste_collection_schedule/.venv/lib/python3.12/site-packages/icalendar/cal.py:582, in Timezone._extract_offsets(component, tzname)
    579 rrstart = dtstart.replace (tzinfo=tzi)
    581 rrulestr = component['RRULE'].to_ical().decode('utf-8')
--> 582 rrule = dateutil.rrule.rrulestr(rrulestr, dtstart=rrstart)
    583 if not {'UNTIL', 'COUNT'}.intersection(component['RRULE'].keys()):
    584     # pytz.timezones don't know any transition dates after 2038
    585     # either
    586     rrule._until = datetime(2038, 12, 31, tzinfo=pytz.UTC)

File ~/Documents/coding/python/hacs_waste_collection_schedule/.venv/lib/python3.12/site-packages/dateutil/rrule.py:1732, in _rrulestr.__call__(self, s, **kwargs)
   1731 def __call__(self, s, **kwargs):
-> 1732     return self._parse_rfc(s, **kwargs)

File ~/Documents/coding/python/hacs_waste_collection_schedule/.venv/lib/python3.12/site-packages/dateutil/rrule.py:1652, in _rrulestr._parse_rfc(self, s, dtstart, cache, unfold, forceset, compatible, ignoretz, tzids, tzinfos)
   1649     lines = s.split()
   1650 if (not forceset and len(lines) == 1 and (s.find(':') == -1 or
   1651                                           s.startswith('RRULE:'))):
-> 1652     return self._parse_rfc_rrule(lines[0], cache=cache,
   1653                                  dtstart=dtstart, ignoretz=ignoretz,
   1654                                  tzinfos=tzinfos)
   1655 else:
   1656     rrulevals = []

File ~/Documents/coding/python/hacs_waste_collection_schedule/.venv/lib/python3.12/site-packages/dateutil/rrule.py:1561, in _rrulestr._parse_rfc_rrule(self, line, dtstart, cache, ignoretz, tzinfos)
   1559     except (KeyError, ValueError):
   1560         raise ValueError("invalid '%s': %s" % (name, value))
-> 1561 return rrule(dtstart=dtstart, cache=cache, **rrkwargs)

File ~/Documents/coding/python/hacs_waste_collection_schedule/.venv/lib/python3.12/site-packages/dateutil/rrule.py:470, in rrule.__init__(self, freq, dtstart, interval, wkst, count, until, bysetpos, bymonth, bymonthday, byyearday, byeaster, byweekno, byweekday, byhour, byminute, bysecond, cache)
    461 if self._dtstart and self._until:
    462     if (self._dtstart.tzinfo is not None) != (self._until.tzinfo is not None):
    463         # According to RFC5545 Section 3.3.10:
    464         # https://tools.ietf.org/html/rfc5545#section-3.3.10
   (...)
    468         # > then the UNTIL rule part MUST be specified as a date with
    469         # > UTC time.
--> 470         raise ValueError(
    471             'RRULE UNTIL values must be specified in UTC when DTSTART '
    472             'is timezone-aware'
    473         )
    475 if count is not None and until:
    476     warn("Using both 'count' and 'until' is inconsistent with RFC 5545"
    477          " and has been deprecated in dateutil. Future versions will "
    478          "raise an error.", DeprecationWarning)

ValueError: RRULE UNTIL values must be specified in UTC when DTSTART is timezone-aware

Expected behavior

Environment

  • OS: Archlinux
  • Python version: Python 3.12.6
  • icalendar version: icalendar==5.0.13

Additional context

  • I tested it with the latest version pip3 install https://github.com/collective/icalendar.git
  • I attached the ICS source file or there is no ICS source file

EDIT:

ICS file from link above

As txt file as GitHub does not allow me to upload a ics file

Abfall_EG_1_Ost_2024.txt

@niccokunzmann
Copy link
Member

niccokunzmann commented Sep 24, 2024

Hi, thanks for reporting this!

I think, it might be worth opening an issue in dateutil, too. I have fixed that in the recurring-ical-events for rrules of events. So, there is code that we could use and push upstream into dateutil to fix this.

@5ila5
Copy link
Author

5ila5 commented Sep 25, 2024

I don't think this is an issue with dateutil
https://github.com/dateutil/dateutil/blob/9eaa5de584f9f374c6e4943069925cc53522ad61/src/dateutil/rrule.py#L463-L469

I just noticed this seems to work when using the git version or the 6.0.0a0 release

So I probably need to wait for a 6.0 release and a new version from icalevents to fully resolve my problem

edit: fixed grammar issue

@5ila5 5ila5 closed this as completed Sep 25, 2024
@niccokunzmann
Copy link
Member

I would keep this open until the error really vanishes. Calendars in the wild sometimes bring on edge cases.

I just noticed this seems to be using the git version or the 6.0.0a0

Yes, we use dateutil then to generate the timezone. So, it is actually good to track, I think.

@niccokunzmann niccokunzmann reopened this Sep 25, 2024
@niccokunzmann
Copy link
Member

I can say that this is indeed a problem but it is removed in v6.0.0 for the zoneinfo impementation. It only occurs with pytz. I wonder if we should fix this then.

@jacadzaca @mauritsvanrees @geier, what is your thought on this: Do we want to fix all problems for pytz or are we only interested in improving the zoneinfo implementation?

I would say that since we are low on actual coding power, we focus only on zoneinfo.

zoneinfo works, pytz fails

>>> for part in c.walk('VTIMEZONE'):
...     print(isinstance(part, Timezone))
...     tz = part.to_tz()
...     print(tz)
... 
True
<tzicalvtz 'Europe/Berlin'>
>>> import icalendar
>>> icalendar.use_pytz()
>>> for part in c.walk('VTIMEZONE'):
KeyboardInterrupt
>>> c = icalendar.Calendar.from_ical(r.text)
ezone
for part in c.walk('VTIMEZONE'):
    print(isinstance(part, Timezone))
    tz = part.to_tz()
    print(tz)>>> part: Timezone
>>> for part in c.walk('VTIMEZONE'):
...     print(isinstance(part, Timezone))
...     tz = part.to_tz()
...     print(tz)
... 
True
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
  File "/home/nicco/icalendar/src/icalendar/cal.py", line 644, in to_tz
    return tzp.create_timezone(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
...
    return rrule(dtstart=dtstart, cache=cache, **rrkwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nicco/icalendar/.venv/lib/python3.12/site-packages/dateutil/rrule.py", line 470, in __init__
    raise ValueError(
ValueError: RRULE UNTIL values must be specified in UTC when DTSTART is timezone-aware

@stevepiercy
Copy link
Member

Plone 6.0 and the latest 6.1 alphas are constrained to icalendar==5.0.12. I don't think we can migrate to v6.0.0 yet. @mauritsvanrees @thet can you help with details?

This might be a bug that does not get fixed until we migrate to icalendar 6.0.0 in Plone 7.0.

@mauritsvanrees
Copy link
Member

In 6.0 we should keep using icalendar 5.
In 6.1 I would want to use icalendar 6 if we can. Probably we should prefer the zoneinfo implementation if Plone can handle it. @thet knows more about possible integration problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants