Support WKST in recurrence rules
RFC 5545 says WKST is significant in weekly rules with nonzero
intervals and BYDAY rules, and also in yearly rules with a BYWEEKNO
part. Yearly with BYWEEKNO seems to be generally broken, so this
only attempts to correct weekly recurrences.
Bug 1641249
Change-Id: Icad8762be4685036fc50bed0cc75970e774a21a8
diff --git a/src/com/android/calendarcommon/EventRecurrence.java b/src/com/android/calendarcommon/EventRecurrence.java
index 57a8c20..b179071 100644
--- a/src/com/android/calendarcommon/EventRecurrence.java
+++ b/src/com/android/calendarcommon/EventRecurrence.java
@@ -581,6 +581,10 @@
* - allows (but ignores) X-* parts
* - improved validation on various values (e.g. UNTIL timestamps)
* - error messages are more specific
+ *
+ * TODO: enforce additional constraints listed in RFC 5545, notably the "N/A" entries
+ * in section 3.3.10. For example, if FREQ=WEEKLY, we should reject a rule that
+ * includes a BYMONTHDAY part.
*/
/* TODO: replace with "if (freq != 0) throw" if nothing requires this */
diff --git a/src/com/android/calendarcommon/RecurrenceProcessor.java b/src/com/android/calendarcommon/RecurrenceProcessor.java
index 577ac49..82b699b 100644
--- a/src/com/android/calendarcommon/RecurrenceProcessor.java
+++ b/src/com/android/calendarcommon/RecurrenceProcessor.java
@@ -904,8 +904,26 @@
// to be before dtstart or after the end, because that will be
// filtered in the inner loop
if (freq == EventRecurrence.WEEKLY) {
- int dow = iterator.weekDay;
- dayIndex = iterator.monthDay - dow;
+ /*
+ * iterator.weekDay indicates the day of the week (0-6, SU-SA).
+ * Because dayIndex might start in the middle of a week, and we're
+ * interested in treating a week as a unit, we want to move
+ * backward to the start of the week. (This could make the
+ * dayIndex negative, which will be corrected by normalization
+ * later on.)
+ *
+ * The day that starts the week is determined by WKST, which
+ * defaults to MO.
+ *
+ * Example: dayIndex is Tuesday the 8th, and weeks start on
+ * Thursdays. Tuesday is day 2, Thursday is day 4, so we
+ * want to move back (2 - 4 + 7) % 7 = 5 days to the previous
+ * Thursday. If weeks started on Mondays, we would only
+ * need to move back (2 - 1 + 7) % 7 = 1 day.
+ */
+ int weekStartAdj = (iterator.weekDay -
+ EventRecurrence.day2TimeDay(r.wkst) + 7) % 7;
+ dayIndex = iterator.monthDay - weekStartAdj;
lastDayToExamine = dayIndex + 6;
} else {
lastDayToExamine = generated
diff --git a/tests/src/com/android/calendarcommon/RecurrenceProcessorTest.java b/tests/src/com/android/calendarcommon/RecurrenceProcessorTest.java
index 21d2d52..ba5ec0c 100644
--- a/tests/src/com/android/calendarcommon/RecurrenceProcessorTest.java
+++ b/tests/src/com/android/calendarcommon/RecurrenceProcessorTest.java
@@ -547,18 +547,10 @@
});
}
- /**
- * This test fails because of a bug in RecurrenceProcessor.expand(). We
- * don't have time to fix the bug yet but we don't want to lose track of
- * this test either. The "failing" prefix on the method name prevents this
- * test from being run. Remove the "failing" prefix when the bug is fixed.
- *
- * @throws Exception
- */
@SmallTest
- public void failingTestWeekly9() throws Exception {
+ public void testWeekly9() throws Exception {
verifyRecurrence("19970805T100000",
- "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=MO",
+ "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU", // uses default WKST=MO
null /* rdate */, null /* exrule */, null /* exdate */,
"19970101T000000", "19980101T000000",
new String[]{
@@ -611,6 +603,34 @@
}
}
+ /**
+ * Test repeating weekly event with dtstart and dtend (only one occurrence)
+ * See bug #3267616
+ * @throws Exception
+ */
+ @SmallTest
+ public void testWeekly13() throws Exception {
+ verifyRecurrence("20101117T150000",
+ "FREQ=WEEKLY;BYDAY=WE",
+ null /* rdate */, null /* exrule */, null /* exdate */,
+ "20101117T150000", "20101117T160000",
+ new String[]{ "20101117T150000" });
+ }
+
+ @SmallTest
+ public void testWeekly14() throws Exception {
+ verifyRecurrence("19970805T100000",
+ "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=TH",
+ null /* rdate */, null /* exrule */, null /* exdate */,
+ "19970101T000000", "19980101T000000",
+ new String[]{
+ "19970805T100000",
+ "19970817T100000",
+ "19970819T100000",
+ "19970831T100000",
+ });
+ }
+
@SmallTest
public void testDaily0() throws Exception {
verifyRecurrence("20060215T100000", "FREQ=DAILY;COUNT=3",
@@ -2397,18 +2417,6 @@
null /* last */);
}
- /**
- * Test repeating weekly event with dtstart and dtend (only one occurrence)
- * See bug #3267616
- * @throws Exception
- */
- public void testWeekly13() throws Exception {
- verifyRecurrence("20101117T150000",
- "FREQ=WEEKLY;BYDAY=WE",
- null /* rdate */, null /* exrule */, null /* exdate */,
- "20101117T150000", "20101117T160000",
- new String[]{ "20101117T150000" });
- }
// These recurrence rules are used in the loop that measures the performance
// of recurrence expansion.