1.1 --- a/vRecurrence.py Sat Oct 04 00:06:07 2014 +0200
1.2 +++ b/vRecurrence.py Sat Oct 04 01:07:46 2014 +0200
1.3 @@ -51,6 +51,7 @@
1.4 resolution (or decreasing scope).
1.5 """
1.6
1.7 +from calendar import monthrange
1.8 from datetime import date, datetime, timedelta
1.9 import operator
1.10
1.11 @@ -299,48 +300,73 @@
1.12 return self.materialise_items(self.context, end, counter)
1.13
1.14 def materialise_item(self, current, next, counter):
1.15 - if self.selecting:
1.16 - return self.selecting.materialise_items(current, next, counter)
1.17 - elif counter is None or counter[0] < counter[1]:
1.18 - if counter is not None:
1.19 - counter[0] += 1
1.20 - return [current]
1.21 + if counter is None or counter[0] < counter[1]:
1.22 + if self.selecting:
1.23 + return self.selecting.materialise_items(current, next, counter)
1.24 + else:
1.25 + if counter is not None:
1.26 + counter[0] += 1
1.27 + return [current]
1.28 else:
1.29 return []
1.30
1.31 class Pattern(Selector):
1.32 def materialise_items(self, context, end, counter):
1.33 - start = self.args["values"][0]
1.34 + first = scale(self.args["values"][0], self.pos)
1.35 +
1.36 + # Define the step between items.
1.37 +
1.38 interval = self.args.get("interval", 1) * units.get(self.qualifier, 1)
1.39 step = scale(interval, self.pos)
1.40 +
1.41 + # Define the scale of a single item.
1.42 +
1.43 unit_interval = units.get(self.qualifier, 1)
1.44 unit_step = scale(unit_interval, self.pos)
1.45 - current = combine(context, scale(start, self.pos))
1.46 +
1.47 + current = combine(context, first)
1.48 results = []
1.49 +
1.50 while current < end and (counter is None or counter[0] < counter[1]):
1.51 next = update(current, step)
1.52 current_end = update(current, unit_step)
1.53 results += self.materialise_item(current, min(current_end, end), counter)
1.54 current = next
1.55 +
1.56 return results
1.57
1.58 class PatternFilter(Selector):
1.59 def materialise_items(self, context, end, counter):
1.60 - start = bases[self.pos]
1.61 + first = scale(bases[self.pos], self.pos)
1.62 +
1.63 + # Define the step between items to be tested.
1.64 +
1.65 step = scale(1, self.pos)
1.66 - current = combine(context, scale(start, self.pos))
1.67 +
1.68 + current = combine(context, first)
1.69 results = []
1.70 +
1.71 while current < end and (counter is None or counter[0] < counter[1]):
1.72 next = update(current, step)
1.73 results += self.materialise_item(current, min(next, end), counter)
1.74 current = next
1.75 +
1.76 return results
1.77
1.78 def materialise_item(self, current, next, counter):
1.79 values = self.args["values"]
1.80 +
1.81 + # Select by day in week, also by occurrence in month.
1.82 +
1.83 if self.qualifier == "BYDAY":
1.84 - if datetime(*current).isoweekday() in values:
1.85 - return Selector.materialise_item(self, current, next, counter)
1.86 + for value, index in values:
1.87 + if datetime(*current).isoweekday() == value:
1.88 + last_day = monthrange(current[0], current[1])[1]
1.89 + index_from_start = (current[2] - 1) / 7
1.90 + index_from_end = -(1 + (last_day - current[2]) / 7)
1.91 + if index is None or index in (index_from_start, index_from_end):
1.92 + return Selector.materialise_item(self, current, next, counter)
1.93 +
1.94 return []
1.95
1.96 class Enum(Selector):