Source code for timetable.event

"""
Functions for generating timetables from raw calendar components. See section
:ref:`timetable` for an explanation of timetables.
"""

from __future__ import absolute_import

from timetable import Recurrence, parse_datetime, timezone


[docs]def uidgroups_by_type(calendar, itemtype): """Selects all items of type *itemtype* in the *calendar* and groups them into a dictionary based on their UID.""" items = {} for item in calendar.items: if item.type != itemtype: continue uid = item[b'uid'][0].value if not uid in items: items[uid] = [] items[uid].append(item) return items
[docs]def generate_item_timetable(uid, group, timezones): """Generates a timetable for a calendar item. The item is given by its *uid* and a list of calendar components in *group*. It is required to supply the *timezones* of the calendar.""" # Find first item without a RECURRENCE-ID entry. for main in group: if not b'recurrence-id' in main: break else: raise ValueError('Invalid item group with UID "%s"' % uid) start = parse_datetime(main[b'dtstart'][0], timezones) if start.tzinfo: start = start.astimezone(timezone.utc).replace(tzinfo=None) if not b'dtend' in main: # Events without a DTEND entry have no duration. end = start else: end = parse_datetime(main[b'dtend'][0], timezones) if end.tzinfo: end = end.astimezone(timezone.utc).replace(tzinfo=None) main_duration = end - start # Collect updates. to_insert = [] to_remove = set() for item in group: # Ignore main item and items without RECURRENCE-ID entries. if item is main or b'recurrence-id' not in item: continue recur_dt = parse_datetime(item[b'recurrence-id'][0], timezones) if recur_dt.tzinfo: recur_dt = recur_dt.astimezone(timezone.utc).replace( tzinfo=None) start = parse_datetime(item[b'dtstart'][0], timezones) if start.tzinfo: start = start.astimezone(timezone.utc).replace(tzinfo=None) end = parse_datetime(item[b'dtend'][0], timezones) if end.tzinfo: end = end.astimezone(timezone.utc).replace(tzinfo=None) to_insert.append((start, end, {'item': item})) to_remove.add(recur_dt) to_insert.sort(key=lambda e: e[0]) for dt in Recurrence(main, timezones)(): # FIXME What timezone to assume to naive datetimes (e.g. on daily # events)? if dt.tzinfo: dt = dt.astimezone(timezone.utc).replace(tzinfo=None) while to_insert and to_insert[0][0] < dt: yield to_insert.pop(0) if dt in to_remove: continue yield dt, dt + main_duration, {'item': main}