From 9451b7f974fb6138fc6e5c66c0e3d3d059ab38e9 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Tue, 13 Dec 2011 03:22:35 +0000 Subject: [PATCH] ALF-11994 Support the Outlook 2010 style of repeating monthly events, with tests git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@32716 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../repo/calendar/CalendarHelpersTest.java | 98 ++++++++++++++++++- .../calendar/CalendarRecurrenceHelper.java | 60 +++++++++--- 2 files changed, 144 insertions(+), 14 deletions(-) diff --git a/source/java/org/alfresco/repo/calendar/CalendarHelpersTest.java b/source/java/org/alfresco/repo/calendar/CalendarHelpersTest.java index 059830d6d6..2b931bfccc 100644 --- a/source/java/org/alfresco/repo/calendar/CalendarHelpersTest.java +++ b/source/java/org/alfresco/repo/calendar/CalendarHelpersTest.java @@ -406,7 +406,7 @@ public class CalendarHelpersTest Map params = new HashMap(); params.put("BYMONTHDAY", "2"); - + // Dates in the past, get nothing dates.clear(); @@ -627,6 +627,102 @@ public class CalendarHelpersTest true, 1); assertEquals(1, dates.size()); assertEquals("2011-08-02", dateFmt.format(dates.get(0))); + + + // Alternate format, used by Outlook 2010 etc + // 1st Monday of the Month + params.clear(); + params.put("FREQ", "MONTHLY"); // Implied in call + params.put("COUNT", "10"); // Implied in call + params.put("INTERVAL", "1"); // Implied in call + params.put("BYDAY", "MO"); + params.put("BYSETPOS", "1"); + + dates.clear(); + currentDate.set(2011,7-1,19,10,30); + RecurrenceHelper.buildMonthlyRecurrences( + currentDate, dates, params, + date(2011,7,19), date(2012,1,5), + false, 1); + assertEquals(6, dates.size()); + assertEquals("2011-08-01", dateFmt.format(dates.get(0))); + assertEquals("2011-09-05", dateFmt.format(dates.get(1))); + assertEquals("2011-10-03", dateFmt.format(dates.get(2))); + assertEquals("2011-11-07", dateFmt.format(dates.get(3))); + assertEquals("2011-12-05", dateFmt.format(dates.get(4))); + assertEquals("2012-01-02", dateFmt.format(dates.get(5))); + + + // 3rd Friday of the Month + params.clear(); + params.put("FREQ", "MONTHLY"); // Implied in call + params.put("COUNT", "10"); // Implied in call + params.put("INTERVAL", "1"); // Implied in call + params.put("BYDAY", "FR"); + params.put("BYSETPOS", "3"); + + dates.clear(); + currentDate.set(2011,7-1,19,10,30); + RecurrenceHelper.buildMonthlyRecurrences( + currentDate, dates, params, + date(2011,7,19), date(2012,1,25), + false, 1); + assertEquals(6, dates.size()); + assertEquals("2011-08-19", dateFmt.format(dates.get(0))); + assertEquals("2011-09-16", dateFmt.format(dates.get(1))); + assertEquals("2011-10-21", dateFmt.format(dates.get(2))); + assertEquals("2011-11-18", dateFmt.format(dates.get(3))); + assertEquals("2011-12-16", dateFmt.format(dates.get(4))); + assertEquals("2012-01-20", dateFmt.format(dates.get(5))); + + + // 3rd Friday of the Month, of every 3 months + params.clear(); + params.put("FREQ", "MONTHLY"); // Implied in call + params.put("COUNT", "10"); // Implied in call + params.put("INTERVAL", "3"); // Implied in call + params.put("BYDAY", "FR"); + params.put("BYSETPOS", "3"); + + dates.clear(); + currentDate.set(2011,7-1,19,10,30); + RecurrenceHelper.buildMonthlyRecurrences( + currentDate, dates, params, + date(2011,7,19), date(2012,1,25), + false, 3); + assertEquals(2, dates.size()); + assertEquals("2011-10-21", dateFmt.format(dates.get(0))); + assertEquals("2012-01-20", dateFmt.format(dates.get(1))); + + + // The third friday falls within the range for this month + dates.clear(); + currentDate.set(2011,7-1,14,10,30); + RecurrenceHelper.buildMonthlyRecurrences( + currentDate, dates, params, + date(2011,7,14), date(2012,1,25), + false, 1); + assertEquals(7, dates.size()); + assertEquals("2011-07-15", dateFmt.format(dates.get(0))); + assertEquals("2011-08-19", dateFmt.format(dates.get(1))); + assertEquals("2011-09-16", dateFmt.format(dates.get(2))); + assertEquals("2011-10-21", dateFmt.format(dates.get(3))); + assertEquals("2011-11-18", dateFmt.format(dates.get(4))); + assertEquals("2011-12-16", dateFmt.format(dates.get(5))); + assertEquals("2012-01-20", dateFmt.format(dates.get(6))); + + + // The third friday falls within the range for this month, every 3 months + dates.clear(); + currentDate.set(2011,7-1,14,10,30); + RecurrenceHelper.buildMonthlyRecurrences( + currentDate, dates, params, + date(2011,7,14), date(2012,1,25), + false, 3); + assertEquals(3, dates.size()); + assertEquals("2011-07-15", dateFmt.format(dates.get(0))); + assertEquals("2011-10-21", dateFmt.format(dates.get(1))); + assertEquals("2012-01-20", dateFmt.format(dates.get(2))); } private static class RecurrenceHelper extends CalendarRecurrenceHelper diff --git a/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java b/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java index f97d684c11..9c3ffcb653 100644 --- a/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java +++ b/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java @@ -398,28 +398,42 @@ public class CalendarRecurrenceHelper } else if (params.get("BYSETPOS") != null) { - // eg the first Thursday of the month - int dayOfWeek = DAY_NAMES_TO_CALENDAR_DAYS.get(params.get("BYSETPOS")); - if (currentDate.get(Calendar.DAY_OF_MONTH) > 8) + // eg the first Thursday of the month, or the third Saturday + int dayOfWeek = -1; + int instanceInMonth = 1; + + // There are two forms... + if (params.containsKey("BYDAY")) { - // Move to start, in next month - addMonthToFirstDayOfWeek(currentDate, dayOfWeek, monthInterval); + dayOfWeek = DAY_NAMES_TO_CALENDAR_DAYS.get(params.get("BYDAY")); + instanceInMonth = Integer.parseInt(params.get("BYSETPOS")); } - else if (currentDate.get(Calendar.DAY_OF_WEEK) != dayOfWeek) + else { - // Move forward to start - Date t = currentDate.getTime(); - currentDate.set(Calendar.DAY_OF_WEEK, dayOfWeek); - if (currentDate.getTime().before(t)) - { - currentDate.add(Calendar.DATE, 7); - } + // Implies the first one in the month + dayOfWeek = DAY_NAMES_TO_CALENDAR_DAYS.get(params.get("BYSETPOS")); + instanceInMonth = 1; } + // Move to the date in this month + Date origDate = currentDate.getTime(); + toDayOfWeekInMonth(currentDate, dayOfWeek, instanceInMonth); + + // If the instance in this month is in the past, go + // forward to the point in the next month + if (currentDate.getTime().before(origDate)) + { + addMonthToFirstDayOfWeek(currentDate, dayOfWeek, monthInterval); + toDayOfWeekInMonth(currentDate, dayOfWeek, instanceInMonth); + } + + // Move forward to the required date while (currentDate.getTime().before(onOrAfter)) { addMonthToFirstDayOfWeek(currentDate, dayOfWeek, monthInterval); + toDayOfWeekInMonth(currentDate, dayOfWeek, instanceInMonth); } + // Roll on until we get valid matches while (true) { if (until != null) @@ -437,6 +451,7 @@ public class CalendarRecurrenceHelper } addMonthToFirstDayOfWeek(currentDate, dayOfWeek, monthInterval); + toDayOfWeekInMonth(currentDate, dayOfWeek, instanceInMonth); } } } @@ -516,6 +531,19 @@ public class CalendarRecurrenceHelper addMonthToDayOfMonth(c, 1, monthInterval); // Set the day of the week + toDayOfWeekInMonth(c, dayOfWeek, 1); + } + + /** + * Takes you to eg the 2nd Thursday in the month, which may + * involve going back before the current date + */ + private static void toDayOfWeekInMonth(Calendar c, int dayOfWeek, int weekInMonth) + { + // First up, move to the start of the month + c.set(Calendar.DATE, 1); + + // Now, move to the 1st instance of the day of the week Date t = c.getTime(); c.set(Calendar.DAY_OF_WEEK, dayOfWeek); // If we went back, go forward a week @@ -523,5 +551,11 @@ public class CalendarRecurrenceHelper { c.add(Calendar.DATE, 7); } + + // Now move to the required week + if (weekInMonth > 1) + { + c.add(Calendar.DATE, 7 * (weekInMonth-1)); + } } }