# HG changeset patch # User Paul Boddie # Date 1423606386 -3600 # Node ID f8538cef6ceda84fb6b9b1c9eab0fbb775df31da # Parent ba6f36a05ef5ca97cb5d9f84819517a6498bfcc7 Changed the get_periods function to use time regime information so that recurring events function across time zone changes. diff -r ba6f36a05ef5 -r f8538cef6ced imiptools/data.py --- a/imiptools/data.py Tue Feb 10 21:53:52 2015 +0100 +++ b/imiptools/data.py Tue Feb 10 23:13:06 2015 +0100 @@ -22,7 +22,7 @@ from datetime import datetime, timedelta from email.mime.text import MIMEText from imiptools.dates import format_datetime, get_datetime, get_freebusy_period, \ - to_utc_datetime + to_timezone, to_utc_datetime from pytz import timezone from vCalendar import iterwrite, parse, ParseError, to_dict, to_node from vRecurrence import get_parameters, get_rule @@ -58,6 +58,10 @@ def get_utc_datetime(self, name): return get_utc_datetime(self.details, name) + def get_datetime(self, name): + dt, attr = get_datetime_item(self.details, name) + return dt + def get_datetime_item(self, name): return get_datetime_item(self.details, name) @@ -80,11 +84,11 @@ # Computed results. - def get_periods(self, window_size=100): - return get_periods(self, window_size) + def get_periods(self, tzid, window_size=100): + return get_periods(self, tzid, window_size) def get_periods_for_freebusy(self, tzid, window_size=100): - periods = self.get_periods(window_size) + periods = self.get_periods(tzid, window_size) return get_periods_for_freebusy(self, periods, tzid) # Construction and serialisation. @@ -287,15 +291,26 @@ # NOTE: Need to expose the 100 day window for recurring events in the # NOTE: configuration. -def get_periods(obj, window_size=100): +def get_periods(obj, tzid, window_size=100): """ Return periods for the given object 'obj', confining materialised periods to the given 'window_size' in days starting from the present moment. """ - dtstart = obj.get_utc_datetime("DTSTART") - dtend = obj.get_utc_datetime("DTEND") + # NOTE: Need also RDATE and EXDATE support. + + rrule = obj.get_value("RRULE") + + if not rrule: + return [(obj.get_utc_datetime("DTSTART"), obj.get_utc_datetime("DTEND"))] + + # Use localised datetimes. + + dtstart, start_attr = obj.get_datetime_item("DTSTART") + dtend, end_attr = obj.get_datetime_item("DTEND") + + tzid = start_attr.get("TZID") or end_attr.get("TZID") or tzid # NOTE: Need also DURATION support. @@ -306,22 +321,17 @@ # for the agent, with instances outside that period being considered # unchecked. - window_end = datetime.now() + timedelta(window_size) + window_end = to_timezone(datetime.now(), tzid) + timedelta(window_size) - # NOTE: Need also RDATE and EXDATE support. - - rrule = obj.get_value("RRULE") + selector = get_rule(dtstart, rrule) + parameters = get_parameters(rrule) + periods = [] - if rrule: - selector = get_rule(dtstart, rrule) - parameters = get_parameters(rrule) - periods = [] - for start in selector.materialise(dtstart, window_end, parameters.get("COUNT"), parameters.get("BYSETPOS")): - start = datetime(*start, tzinfo=timezone("UTC")) - end = start + duration - periods.append((start, end)) - else: - periods = [(dtstart, dtend)] + for start in selector.materialise(dtstart, window_end, parameters.get("COUNT"), parameters.get("BYSETPOS")): + start = to_timezone(datetime(*start), tzid) + start = to_timezone(start, "UTC") + end = start + duration + periods.append((start, end)) return periods