diff -r dee028db6e9b -r 73bdfa70b04e src/net/fortuna/ical4j/model/Recur.java --- a/src/net/fortuna/ical4j/model/Recur.java Tue Feb 10 19:25:00 2015 +0100 +++ b/src/net/fortuna/ical4j/model/Recur.java Tue Feb 10 19:38:00 2015 +0100 @@ -44,6 +44,7 @@ import java.util.StringTokenizer; import net.fortuna.ical4j.model.parameter.Value; +import net.fortuna.ical4j.util.CompatibilityHints; import net.fortuna.ical4j.util.Configurator; import net.fortuna.ical4j.util.Dates; @@ -171,6 +172,8 @@ private NumberList setPosList; private String weekStartDay; + + private int calendarWeekStartDay; private Map experimentalValues = new HashMap(); @@ -181,6 +184,8 @@ * Default constructor. */ public Recur() { + // default week start is Monday per RFC5545 + calendarWeekStartDay = Calendar.MONDAY; } /** @@ -189,6 +194,8 @@ * @throws ParseException thrown when the specified string contains an invalid representation of an UNTIL date value */ public Recur(final String aValue) throws ParseException { + // default week start is Monday per RFC5545 + calendarWeekStartDay = Calendar.MONDAY; final StringTokenizer t = new StringTokenizer(aValue, ";="); while (t.hasMoreTokens()) { final String token = t.nextToken(); @@ -241,10 +248,17 @@ } else if (WKST.equals(token)) { weekStartDay = nextToken(t, token); + calendarWeekStartDay = WeekDay.getCalendarDay(new WeekDay(weekStartDay)); } - // assume experimental value.. else { - experimentalValues.put(token, nextToken(t, token)); + if (CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING)) { + // assume experimental value.. + experimentalValues.put(token, nextToken(t, token)); + } + else { + throw new IllegalArgumentException("Invalid recurrence rule part: " + + token + "=" + nextToken(t, token)); + } } } validateFrequency(); @@ -264,6 +278,8 @@ * @param until maximum recurrence date */ public Recur(final String frequency, final Date until) { + // default week start is Monday per RFC5545 + calendarWeekStartDay = Calendar.MONDAY; this.frequency = frequency; this.until = until; validateFrequency(); @@ -274,6 +290,8 @@ * @param count maximum recurrence count */ public Recur(final String frequency, final int count) { + // default week start is Monday per RFC5545 + calendarWeekStartDay = Calendar.MONDAY; this.frequency = frequency; this.count = count; validateFrequency(); @@ -416,6 +434,9 @@ */ public final void setWeekStartDay(final String weekStartDay) { this.weekStartDay = weekStartDay; + if (weekStartDay != null) { + calendarWeekStartDay = WeekDay.getCalendarDay(new WeekDay(weekStartDay)); + } } /** @@ -578,8 +599,7 @@ dates.setTimeZone(((DateTime) seed).getTimeZone()); } } - final Calendar cal = Dates.getCalendarInstance(seed); - cal.setTime(seed); + final Calendar cal = getCalendarInstance(seed, true); // optimize the start time for selecting candidates // (only applicable where a COUNT is not specified) @@ -670,8 +690,7 @@ */ public final Date getNextDate(final Date seed, final Date startDate) { - final Calendar cal = Dates.getCalendarInstance(seed); - cal.setTime(seed); + final Calendar cal = getCalendarInstance(seed, true); // optimize the start time for selecting candidates // (only applicable where a COUNT is not specified) @@ -857,8 +876,8 @@ final DateList monthlyDates = getDateListInstance(dates); for (final Iterator i = dates.iterator(); i.hasNext();) { final Date date = (Date) i.next(); - final Calendar cal = Dates.getCalendarInstance(date); - cal.setTime(date); + final Calendar cal = getCalendarInstance(date, true); + for (final Iterator j = getMonthList().iterator(); j.hasNext();) { final Integer month = (Integer) j.next(); // Java months are zero-based.. @@ -883,8 +902,7 @@ final DateList weekNoDates = getDateListInstance(dates); for (final Iterator i = dates.iterator(); i.hasNext();) { final Date date = (Date) i.next(); - final Calendar cal = Dates.getCalendarInstance(date); - cal.setTime(date); + final Calendar cal = getCalendarInstance(date, true); for (final Iterator j = getWeekNoList().iterator(); j.hasNext();) { final Integer weekNo = (Integer) j.next(); cal.set(Calendar.WEEK_OF_YEAR, Dates.getAbsWeekNo(cal.getTime(), weekNo.intValue())); @@ -907,8 +925,7 @@ final DateList yearDayDates = getDateListInstance(dates); for (final Iterator i = dates.iterator(); i.hasNext();) { final Date date = (Date) i.next(); - final Calendar cal = Dates.getCalendarInstance(date); - cal.setTime(date); + final Calendar cal = getCalendarInstance(date, true); for (final Iterator j = getYearDayList().iterator(); j.hasNext();) { final Integer yearDay = (Integer) j.next(); cal.set(Calendar.DAY_OF_YEAR, Dates.getAbsYearDay(cal.getTime(), yearDay.intValue())); @@ -931,9 +948,7 @@ final DateList monthDayDates = getDateListInstance(dates); for (final Iterator i = dates.iterator(); i.hasNext();) { final Date date = (Date) i.next(); - final Calendar cal = Dates.getCalendarInstance(date); - cal.setLenient(false); - cal.setTime(date); + final Calendar cal = getCalendarInstance(date, false); for (final Iterator j = getMonthDayList().iterator(); j.hasNext();) { final Integer monthDay = (Integer) j.next(); try { @@ -969,8 +984,7 @@ // if BYYEARDAY or BYMONTHDAY is specified filter existing // list.. if (!getYearDayList().isEmpty() || !getMonthDayList().isEmpty()) { - final Calendar cal = Dates.getCalendarInstance(date); - cal.setTime(date); + final Calendar cal = getCalendarInstance(date, true); if (weekDay.equals(WeekDay.getWeekDay(cal))) { weekDayDates.add(date); } @@ -991,15 +1005,7 @@ * @return */ private List getAbsWeekDays(final Date date, final Value type, final WeekDay weekDay) { - final Calendar cal = Dates.getCalendarInstance(date); - // default week start is Monday per RFC5545 - int calendarWeekStartDay = Calendar.MONDAY; - if (weekStartDay != null) { - calendarWeekStartDay = WeekDay.getCalendarDay(new WeekDay(weekStartDay)); - } - cal.setFirstDayOfWeek(calendarWeekStartDay); - cal.setTime(date); - + final Calendar cal = getCalendarInstance(date, true); final DateList days = new DateList(type); if (date instanceof DateTime) { if (((DateTime) date).isUtc()) { @@ -1095,8 +1101,7 @@ final DateList hourlyDates = getDateListInstance(dates); for (final Iterator i = dates.iterator(); i.hasNext();) { final Date date = (Date) i.next(); - final Calendar cal = Dates.getCalendarInstance(date); - cal.setTime(date); + final Calendar cal = getCalendarInstance(date, true); for (final Iterator j = getHourList().iterator(); j.hasNext();) { final Integer hour = (Integer) j.next(); cal.set(Calendar.HOUR_OF_DAY, hour.intValue()); @@ -1119,8 +1124,7 @@ final DateList minutelyDates = getDateListInstance(dates); for (final Iterator i = dates.iterator(); i.hasNext();) { final Date date = (Date) i.next(); - final Calendar cal = Dates.getCalendarInstance(date); - cal.setTime(date); + final Calendar cal = getCalendarInstance(date, true); for (final Iterator j = getMinuteList().iterator(); j.hasNext();) { final Integer minute = (Integer) j.next(); cal.set(Calendar.MINUTE, minute.intValue()); @@ -1143,8 +1147,7 @@ final DateList secondlyDates = getDateListInstance(dates); for (final Iterator i = dates.iterator(); i.hasNext();) { final Date date = (Date) i.next(); - final Calendar cal = Dates.getCalendarInstance(date); - cal.setTime(date); + final Calendar cal = getCalendarInstance(date, true); for (final Iterator j = getSecondList().iterator(); j.hasNext();) { final Integer second = (Integer) j.next(); cal.set(Calendar.SECOND, second.intValue()); @@ -1218,6 +1221,23 @@ } /** + * Construct a Calendar object and sets the time. + * @param date + * @param lenient + * @return + */ + private Calendar getCalendarInstance(final Date date, final boolean lenient) { + Calendar cal = Dates.getCalendarInstance(date); + // A week should have at least 4 days to be considered as such per RFC5545 + cal.setMinimalDaysInFirstWeek(4); + cal.setFirstDayOfWeek(calendarWeekStartDay); + cal.setLenient(lenient); + cal.setTime(date); + + return cal; + } + + /** * @param stream * @throws IOException * @throws ClassNotFoundException @@ -1233,7 +1253,7 @@ * @param origList * @return a new empty list. */ - private static final DateList getDateListInstance(final DateList origList) { + private static DateList getDateListInstance(final DateList origList) { final DateList list = new DateList(origList.getType()); if (origList.isUtc()) { list.setUtc(true);