1.1 --- a/tests/qualifiers.py Sat Oct 04 00:06:07 2014 +0200
1.2 +++ b/tests/qualifiers.py Sat Oct 04 01:07:46 2014 +0200
1.3 @@ -29,7 +29,7 @@
1.4 qualifiers = [
1.5 ("YEARLY", {"interval" : 2}),
1.6 ("BYMONTH", {"values" : [1]}),
1.7 - ("BYDAY", {"values" : [6]}),
1.8 + ("BYDAY", {"values" : [(6, None)]}),
1.9 ("BYHOUR", {"values" : [8, 9]}),
1.10 ("BYMINUTE", {"values" : [30]})
1.11 ]
1.12 @@ -147,7 +147,7 @@
1.13 qualifiers = [
1.14 ("YEARLY", {"interval" : 1}),
1.15 ("BYMONTH", {"values" : [1]}),
1.16 - ("BYDAY", {"values" : [1, 2, 3, 4, 5, 6, 7]})
1.17 + ("BYDAY", {"values" : [(1, None), (2, None), (3, None), (4, None), (5, None), (6, None), (7, None)]})
1.18 ]
1.19
1.20 l = order_qualifiers(qualifiers)
1.21 @@ -244,7 +244,7 @@
1.22
1.23 qualifiers = [
1.24 ("WEEKLY", {"interval" : 1}),
1.25 - ("BYDAY", {"values" : [2, 4]})
1.26 + ("BYDAY", {"values" : [(2, None), (4, None)]})
1.27 ]
1.28
1.29 l = order_qualifiers(qualifiers)
1.30 @@ -264,7 +264,7 @@
1.31
1.32 qualifiers = [
1.33 ("WEEKLY", {"interval" : 1}),
1.34 - ("BYDAY", {"values" : [2, 4]})
1.35 + ("BYDAY", {"values" : [(2, None), (4, None)]})
1.36 ]
1.37
1.38 l = order_qualifiers(qualifiers)
1.39 @@ -284,7 +284,7 @@
1.40
1.41 qualifiers = [
1.42 ("WEEKLY", {"interval" : 2}),
1.43 - ("BYDAY", {"values" : [1, 3, 5]})
1.44 + ("BYDAY", {"values" : [(1, None), (3, None), (5, None)]})
1.45 ]
1.46
1.47 l = order_qualifiers(qualifiers)
1.48 @@ -302,4 +302,104 @@
1.49 print l[-1] == (1997, 12, 22, 9, 0, 0), l[-1]
1.50 print
1.51
1.52 +qualifiers = [
1.53 + ("WEEKLY", {"interval" : 2}),
1.54 + ("BYDAY", {"values" : [(2, None), (4, None)]})
1.55 + ]
1.56 +
1.57 +l = order_qualifiers(qualifiers)
1.58 +show(l)
1.59 +dt = (1997, 9, 2, 9, 0, 0)
1.60 +l = get_datetime_structure(dt)
1.61 +show(l)
1.62 +l = combine_datetime_with_qualifiers(dt, qualifiers)
1.63 +show(l)
1.64 +
1.65 +s = process(l)
1.66 +l = s.materialise((1997, 12, 24, 0, 0, 0), 8)
1.67 +print len(l) == 8, len(l)
1.68 +print l[0] == (1997, 9, 2, 9, 0, 0), l[0]
1.69 +print l[-1] == (1997, 10, 16, 9, 0, 0), l[-1]
1.70 +print
1.71 +
1.72 +qualifiers = [
1.73 + ("MONTHLY", {"interval" : 1}),
1.74 + ("BYDAY", {"values" : [(5, 0)]})
1.75 + ]
1.76 +
1.77 +l = order_qualifiers(qualifiers)
1.78 +show(l)
1.79 +dt = (1997, 9, 5, 9, 0, 0)
1.80 +l = get_datetime_structure(dt)
1.81 +show(l)
1.82 +l = combine_datetime_with_qualifiers(dt, qualifiers)
1.83 +show(l)
1.84 +
1.85 +s = process(l)
1.86 +l = s.materialise((1998, 12, 24, 0, 0, 0), 10)
1.87 +print len(l) == 10, len(l)
1.88 +print l[0] == (1997, 9, 5, 9, 0, 0), l[0]
1.89 +print l[-1] == (1998, 6, 5, 9, 0, 0), l[-1]
1.90 +print
1.91 +
1.92 +qualifiers = [
1.93 + ("MONTHLY", {"interval" : 1}),
1.94 + ("BYDAY", {"values" : [(5, 0)]})
1.95 + ]
1.96 +
1.97 +l = order_qualifiers(qualifiers)
1.98 +show(l)
1.99 +dt = (1997, 9, 5, 9, 0, 0)
1.100 +l = get_datetime_structure(dt)
1.101 +show(l)
1.102 +l = combine_datetime_with_qualifiers(dt, qualifiers)
1.103 +show(l)
1.104 +
1.105 +s = process(l)
1.106 +l = s.materialise((1997, 12, 24, 0, 0, 0))
1.107 +print len(l) == 4, len(l)
1.108 +print l[0] == (1997, 9, 5, 9, 0, 0), l[0]
1.109 +print l[-1] == (1997, 12, 5, 9, 0, 0), l[-1]
1.110 +print
1.111 +
1.112 +qualifiers = [
1.113 + ("MONTHLY", {"interval" : 2}),
1.114 + ("BYDAY", {"values" : [(7, 0), (7, -1)]})
1.115 + ]
1.116 +
1.117 +l = order_qualifiers(qualifiers)
1.118 +show(l)
1.119 +dt = (1997, 9, 7, 9, 0, 0)
1.120 +l = get_datetime_structure(dt)
1.121 +show(l)
1.122 +l = combine_datetime_with_qualifiers(dt, qualifiers)
1.123 +show(l)
1.124 +
1.125 +s = process(l)
1.126 +l = s.materialise((1998, 12, 24, 0, 0, 0), 10)
1.127 +print len(l) == 10, len(l)
1.128 +print l[0] == (1997, 9, 7, 9, 0, 0), l[0]
1.129 +print l[-1] == (1998, 5, 31, 9, 0, 0), l[-1]
1.130 +print
1.131 +
1.132 +qualifiers = [
1.133 + ("MONTHLY", {"interval" : 1}),
1.134 + ("BYDAY", {"values" : [(1, -2)]})
1.135 + ]
1.136 +
1.137 +l = order_qualifiers(qualifiers)
1.138 +show(l)
1.139 +dt = (1997, 9, 22, 9, 0, 0)
1.140 +l = get_datetime_structure(dt)
1.141 +show(l)
1.142 +l = combine_datetime_with_qualifiers(dt, qualifiers)
1.143 +show(l)
1.144 +
1.145 +s = process(l)
1.146 +l = s.materialise((1998, 12, 24, 0, 0, 0), 6)
1.147 +print len(l) == 6, len(l)
1.148 +print l[0] == (1997, 9, 22, 9, 0, 0), l[0]
1.149 +print l[-1] == (1998, 2, 16, 9, 0, 0), l[-1]
1.150 +print
1.151 +
1.152 # vim: tabstop=4 expandtab shiftwidth=4
2.1 --- a/vRecurrence.py Sat Oct 04 00:06:07 2014 +0200
2.2 +++ b/vRecurrence.py Sat Oct 04 01:07:46 2014 +0200
2.3 @@ -51,6 +51,7 @@
2.4 resolution (or decreasing scope).
2.5 """
2.6
2.7 +from calendar import monthrange
2.8 from datetime import date, datetime, timedelta
2.9 import operator
2.10
2.11 @@ -299,48 +300,73 @@
2.12 return self.materialise_items(self.context, end, counter)
2.13
2.14 def materialise_item(self, current, next, counter):
2.15 - if self.selecting:
2.16 - return self.selecting.materialise_items(current, next, counter)
2.17 - elif counter is None or counter[0] < counter[1]:
2.18 - if counter is not None:
2.19 - counter[0] += 1
2.20 - return [current]
2.21 + if counter is None or counter[0] < counter[1]:
2.22 + if self.selecting:
2.23 + return self.selecting.materialise_items(current, next, counter)
2.24 + else:
2.25 + if counter is not None:
2.26 + counter[0] += 1
2.27 + return [current]
2.28 else:
2.29 return []
2.30
2.31 class Pattern(Selector):
2.32 def materialise_items(self, context, end, counter):
2.33 - start = self.args["values"][0]
2.34 + first = scale(self.args["values"][0], self.pos)
2.35 +
2.36 + # Define the step between items.
2.37 +
2.38 interval = self.args.get("interval", 1) * units.get(self.qualifier, 1)
2.39 step = scale(interval, self.pos)
2.40 +
2.41 + # Define the scale of a single item.
2.42 +
2.43 unit_interval = units.get(self.qualifier, 1)
2.44 unit_step = scale(unit_interval, self.pos)
2.45 - current = combine(context, scale(start, self.pos))
2.46 +
2.47 + current = combine(context, first)
2.48 results = []
2.49 +
2.50 while current < end and (counter is None or counter[0] < counter[1]):
2.51 next = update(current, step)
2.52 current_end = update(current, unit_step)
2.53 results += self.materialise_item(current, min(current_end, end), counter)
2.54 current = next
2.55 +
2.56 return results
2.57
2.58 class PatternFilter(Selector):
2.59 def materialise_items(self, context, end, counter):
2.60 - start = bases[self.pos]
2.61 + first = scale(bases[self.pos], self.pos)
2.62 +
2.63 + # Define the step between items to be tested.
2.64 +
2.65 step = scale(1, self.pos)
2.66 - current = combine(context, scale(start, self.pos))
2.67 +
2.68 + current = combine(context, first)
2.69 results = []
2.70 +
2.71 while current < end and (counter is None or counter[0] < counter[1]):
2.72 next = update(current, step)
2.73 results += self.materialise_item(current, min(next, end), counter)
2.74 current = next
2.75 +
2.76 return results
2.77
2.78 def materialise_item(self, current, next, counter):
2.79 values = self.args["values"]
2.80 +
2.81 + # Select by day in week, also by occurrence in month.
2.82 +
2.83 if self.qualifier == "BYDAY":
2.84 - if datetime(*current).isoweekday() in values:
2.85 - return Selector.materialise_item(self, current, next, counter)
2.86 + for value, index in values:
2.87 + if datetime(*current).isoweekday() == value:
2.88 + last_day = monthrange(current[0], current[1])[1]
2.89 + index_from_start = (current[2] - 1) / 7
2.90 + index_from_end = -(1 + (last_day - current[2]) / 7)
2.91 + if index is None or index in (index_from_start, index_from_end):
2.92 + return Selector.materialise_item(self, current, next, counter)
2.93 +
2.94 return []
2.95
2.96 class Enum(Selector):