This commit is contained in:
Timothy Jaeryang Baek committed 2026-08-29 16:14:32 -04:00
1 parent 348751b6a5
commit a93c508038
3 files changed
+46 -16

No files matched your search

+13 -14
View File
@@ -8,6 +8,7 @@ import datetime as dt
import logging
from zoneinfo import ZoneInfo
from dateutil.rrule import rrulestr
from open_webui.utils.automations import _resolve_tz
log = logging.getLogger(__name__)
@@ -25,18 +26,17 @@ def expand_recurring_event(
Takes an event dict (from CalendarEventModel.model_dump()) and produces
one dict per occurrence, with adjusted start_at / end_at.
"""
from dateutil.rrule import rrulestr
rrule_str = event_dict.get('rrule')
if not rrule_str:
return [event_dict]
if 'EXRULE' in rrule_str.upper():
log.warning(f'EXRULE is not supported for event {event_dict.get("id")}: {rrule_str}')
return [event_dict]
user_timezone = _resolve_tz(tz)
def to_local_datetime(timestamp_ns: int) -> dt.datetime:
if user_timezone:
return dt.datetime.fromtimestamp(timestamp_ns / 1_000_000_000, tz=user_timezone).replace(tzinfo=None)
return dt.datetime.fromtimestamp(timestamp_ns / 1_000_000_000)
return dt.datetime.fromtimestamp(timestamp_ns / 1_000_000_000, tz=user_timezone).replace(tzinfo=None)
range_start = to_local_datetime(range_start_ns)
range_end = to_local_datetime(range_end_ns)
@@ -44,10 +44,11 @@ def expand_recurring_event(
original_start_ns = event_dict['start_at']
original_start = to_local_datetime(original_start_ns)
rule_str = '\n'.join(line for line in rrule_str.splitlines() if not line.upper().startswith('DTSTART')) or rrule_str
try:
# Anchor to the event's real start so day-of-week / day-of-month are correct
rule = rrulestr(rrule_str, dtstart=original_start, ignoretz=True)
rule = rrulestr(rule_str, dtstart=original_start, ignoretz=True)
except Exception:
log.warning(f'Failed to parse RRULE for event {event_dict.get("id")}: {rrule_str}')
return [event_dict]
@@ -56,13 +57,13 @@ def expand_recurring_event(
duration_ns = (original_end_ns - original_start_ns) if original_end_ns else None
instances = []
occurrence_start = rule.after(scan_start, inc=True)
previous_start = None
for occurrence_start in rule.xafter(scan_start, count=max_instances, inc=True):
if occurrence_start >= range_end or occurrence_start == previous_start:
break
previous_start = occurrence_start
while occurrence_start and occurrence_start < range_end and len(instances) < max_instances:
if user_timezone:
instance_start_ns = int(occurrence_start.replace(tzinfo=user_timezone).timestamp() * 1_000_000_000)
else:
instance_start_ns = int(occurrence_start.timestamp() * 1_000_000_000)
instance_start_ns = int(occurrence_start.replace(tzinfo=user_timezone).timestamp() * 1_000_000_000)
if instance_start_ns >= range_start_ns:
instance = {
@@ -73,8 +74,6 @@ def expand_recurring_event(
}
instances.append(instance)
occurrence_start = rule.after(occurrence_start)
return instances