1.1 --- a/imiptools/data.py Sun Mar 22 22:08:20 2015 +0100
1.2 +++ b/imiptools/data.py Sun Mar 22 23:43:18 2015 +0100
1.3 @@ -19,6 +19,7 @@
1.4 this program. If not, see <http://www.gnu.org/licenses/>.
1.5 """
1.6
1.7 +from bisect import bisect_left
1.8 from datetime import datetime, timedelta
1.9 from email.mime.text import MIMEText
1.10 from imiptools.dates import format_datetime, get_datetime, get_duration, \
1.11 @@ -100,14 +101,14 @@
1.12 # Computed results.
1.13
1.14 def has_recurrence(self, tzid, recurrence):
1.15 - recurrences = [start for start, end in get_periods(self, tzid, recurrence, True)]
1.16 + recurrences = [start for start, end in get_periods(self, tzid, recurrence, inclusive=True)]
1.17 return recurrence in recurrences
1.18
1.19 - def get_periods(self, tzid, end):
1.20 - return get_periods(self, tzid, end)
1.21 + def get_periods(self, tzid, end, origin=False):
1.22 + return get_periods(self, tzid, end, origin=origin)
1.23
1.24 - def get_periods_for_freebusy(self, tzid, end):
1.25 - periods = self.get_periods(tzid, end)
1.26 + def get_periods_for_freebusy(self, tzid, end, origin=False):
1.27 + periods = self.get_periods(tzid, end, origin)
1.28 return get_periods_for_freebusy(self, periods, tzid)
1.29
1.30 def get_tzid(self):
1.31 @@ -367,12 +368,16 @@
1.32 def get_tzid(dtstart_attr, dtend_attr):
1.33 return dtstart_attr.get("TZID") or dtend_attr.get("TZID")
1.34
1.35 -def get_periods(obj, tzid, window_end, inclusive=False):
1.36 +def get_periods(obj, tzid, window_end, inclusive=False, origin=False):
1.37
1.38 """
1.39 Return periods for the given object 'obj', confining materialised periods
1.40 to before the given 'window_end' datetime. If 'inclusive' is set to a true
1.41 value, any period occurring at the 'window_end' will be included.
1.42 +
1.43 + If 'origin' is set to a true value, the property type providing each period
1.44 + will be included in the results, with each result taking the form
1.45 + (start, end, property type).
1.46 """
1.47
1.48 rrule = obj.get_value("RRULE")
1.49 @@ -394,7 +399,8 @@
1.50 tzid = get_tzid(dtstart_attr, dtend_attr) or tzid
1.51
1.52 if not rrule:
1.53 - periods = [(dtstart, dtend)]
1.54 + origin_value = origin and ("DTSTART",) or ()
1.55 + periods = [(dtstart, dtend) + origin_value]
1.56 else:
1.57 # Recurrence rules create multiple instances to be checked.
1.58 # Conflicts may only be assessed within a period defined by policy
1.59 @@ -403,12 +409,13 @@
1.60
1.61 selector = get_rule(dtstart, rrule)
1.62 parameters = get_parameters(rrule)
1.63 + origin_value = origin and ("RRULE",) or ()
1.64 periods = []
1.65
1.66 for start in selector.materialise(dtstart, window_end, parameters.get("COUNT"), parameters.get("BYSETPOS"), inclusive):
1.67 start = to_timezone(datetime(*start), tzid)
1.68 end = start + duration
1.69 - periods.append((start, end))
1.70 + periods.append((start, end) + origin_value)
1.71
1.72 # Add recurrence dates.
1.73
1.74 @@ -416,11 +423,17 @@
1.75 rdates = obj.get_date_values("RDATE", tzid)
1.76
1.77 if rdates:
1.78 + origin_value = origin and ("RDATE",) or ()
1.79 for rdate in rdates:
1.80 if isinstance(rdate, tuple):
1.81 - periods.add(rdate)
1.82 + periods.add(rdate + origin_value)
1.83 else:
1.84 - periods.add((rdate, rdate + duration))
1.85 + periods.add((rdate, rdate + duration) + origin_value)
1.86 +
1.87 + # Return a sorted list of the periods.
1.88 +
1.89 + periods = list(periods)
1.90 + periods.sort()
1.91
1.92 # Exclude exception dates.
1.93
1.94 @@ -432,13 +445,10 @@
1.95 period = exdate
1.96 else:
1.97 period = (exdate, exdate + duration)
1.98 - if period in periods:
1.99 - periods.remove(period)
1.100 + i = bisect_left(periods, period)
1.101 + while i < len(periods) and periods[i][:2] == period:
1.102 + del periods[i]
1.103
1.104 - # Return a sorted list of the periods.
1.105 -
1.106 - periods = list(periods)
1.107 - periods.sort()
1.108 return periods
1.109
1.110 def get_periods_for_freebusy(obj, periods, tzid):
1.111 @@ -461,10 +471,11 @@
1.112
1.113 l = []
1.114
1.115 - for start, end in periods:
1.116 + for t in periods:
1.117 + start, end = t[:2]
1.118 start, end = get_freebusy_period(start, end, tzid)
1.119 start, end = [to_timezone(x, "UTC") for x in start, end]
1.120 - l.append((format_datetime(start), format_datetime(end)))
1.121 + l.append((format_datetime(start), format_datetime(end)) + t[2:])
1.122
1.123 return l
1.124