public void testSubDailyFreqs() throws ParseException { task.setValue(Task.DUE_DATE, DateUtilities.now() - DateUtilities.ONE_WEEK); task.setFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION, true); for (Frequency freq : Frequency.values()) { long interval = -1; switch (freq) { case MINUTELY: interval = DateUtilities.ONE_MINUTE; break; case HOURLY: interval = DateUtilities.ONE_HOUR; break; default: continue; } buildRRule(1, freq); nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal()); buildRRule(6, freq); nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal()); assertDateTimeEquals(freq.toString() + "x6", DateUtilities.now() + 6 * interval, nextDueDate); task.setValue(Task.DUE_DATE, nextDueDate); assertTrue(task.hasDueTime()); } }
/** Initialize RRule instance */ private static RRule initRRule(String recurrence) throws ParseException { RRule rrule = new RRule(recurrence); // handle the iCalendar "byDay" field differently depending on if // we are weekly or otherwise if (rrule.getFreq() != Frequency.WEEKLY) rrule.setByDay(Collections.EMPTY_LIST); return rrule; }
static long handleSubdayRepeat(DateTime startDate, RRule rrule) { long millis; switch (rrule.getFreq()) { case HOURLY: millis = DateUtilities.ONE_HOUR; break; case MINUTELY: millis = DateUtilities.ONE_MINUTE; break; default: throw new RuntimeException( "Error handing subday repeat: " + rrule.getFreq()); // $NON-NLS-1$ } long newDueDate = startDate.getMillis() + millis * rrule.getInterval(); return Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, newDueDate); }
public void testDailyAndGreaterFreqs() throws ParseException { task.setValue( Task.DUE_DATE, Task.createDueDate( Task.URGENCY_SPECIFIC_DAY, DateUtilities.now() - DateUtilities.ONE_WEEK)); task.setFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION, true); for (int interval = 1; interval < 7; interval++) { for (Frequency freq : Frequency.values()) { long next = DateUtilities.now(); switch (freq) { case DAILY: next += interval * DateUtilities.ONE_DAY; break; case WEEKLY: next += interval * DateUtilities.ONE_WEEK; break; case MONTHLY: next = DateUtilities.addCalendarMonthsToUnixtime(next, interval); break; case YEARLY: next = DateUtilities.addCalendarMonthsToUnixtime(next, interval * 12); break; default: continue; } buildRRule(interval, freq); nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal()); assertDateEquals(freq.toString() + "x" + interval, next, nextDueDate); task.setValue(Task.DUE_DATE, nextDueDate); assertFalse(task.hasDueTime()); } } }
public void testTimeZoneLate() throws ParseException { TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); task.setValue(Task.DUE_DATE, DateUtilities.now() + DateUtilities.ONE_WEEK); task.setFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION, true); nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal()); long expected = Task.createDueDate(Task.URGENCY_TOMORROW, 0); assertDateEquals("tomorrow", expected, nextDueDate); }
// Parses through the text and sets the frequency of the task. private static boolean repeatHelper(Task task) { if (task.containsNonNullValue(Task.RECURRENCE)) { return false; } String inputText = task.getValue(Task.TITLE); HashMap<String, Frequency> repeatTimes = new HashMap<String, Frequency>(); repeatTimes.put("(?i)\\bevery ?\\w{0,6} days?\\b", Frequency.DAILY); repeatTimes.put("(?i)\\bevery ?\\w{0,6} ?nights?\\b", Frequency.DAILY); repeatTimes.put("(?i)\\bevery ?\\w{0,6} ?mornings?\\b", Frequency.DAILY); repeatTimes.put("(?i)\\bevery ?\\w{0,6} ?evenings?\\b", Frequency.DAILY); repeatTimes.put("(?i)\\bevery ?\\w{0,6} ?afternoons?\\b", Frequency.DAILY); repeatTimes.put("(?i)\\bevery \\w{0,6} ?weeks?\\b", Frequency.WEEKLY); repeatTimes.put( "(?i)\\bevery \\w{0,6} ?(mon|tues|wednes|thurs|fri|satur|sun)days?\\b", Frequency.WEEKLY); repeatTimes.put("(?i)\\bevery \\w{0,6} ?months?\\b", Frequency.MONTHLY); repeatTimes.put("(?i)\\bevery \\w{0,6} ?years?\\b", Frequency.YEARLY); HashMap<String, Frequency> repeatTimesIntervalOne = new HashMap<String, Frequency>(); // pre-determined intervals of 1 repeatTimesIntervalOne.put("(?i)\\bdaily\\b", Frequency.DAILY); repeatTimesIntervalOne.put("(?i)\\beveryday\\b", Frequency.DAILY); repeatTimesIntervalOne.put("(?i)\\bweekly\\b", Frequency.WEEKLY); repeatTimesIntervalOne.put("(?i)\\bmonthly\\b", Frequency.MONTHLY); repeatTimesIntervalOne.put("(?i)\\byearly\\b", Frequency.YEARLY); Set<String> keys = repeatTimes.keySet(); for (String repeatTime : keys) { Pattern pattern = Pattern.compile(repeatTime); Matcher m = pattern.matcher(inputText); if (m.find()) { Frequency rtime = repeatTimes.get(repeatTime); RRule rrule = new RRule(); rrule.setFreq(rtime); rrule.setInterval(findInterval(inputText)); task.setValue(Task.RECURRENCE, rrule.toIcal()); return true; } } for (String repeatTimeIntervalOne : repeatTimesIntervalOne.keySet()) { Pattern pattern = Pattern.compile(repeatTimeIntervalOne); Matcher m = pattern.matcher(inputText); if (m.find()) { Frequency rtime = repeatTimesIntervalOne.get(repeatTimeIntervalOne); RRule rrule = new RRule(); rrule.setFreq(rtime); rrule.setInterval(1); String thing = rrule.toIcal(); task.setValue(Task.RECURRENCE, thing); return true; } } return false; }
private static long handleWeeklyRepeatAfterComplete( RRule rrule, Date original, boolean hasDueTime) { List<WeekdayNum> byDay = rrule.getByDay(); long newDate = original.getTime(); newDate += DateUtilities.ONE_WEEK * (rrule.getInterval() - 1); Calendar date = Calendar.getInstance(); date.setTimeInMillis(newDate); Collections.sort(byDay, weekdayCompare); WeekdayNum next = findNextWeekday(byDay, date); do { date.add(Calendar.DATE, 1); } while (date.get(Calendar.DAY_OF_WEEK) != next.wday.javaDayNum); long time = date.getTimeInMillis(); if (hasDueTime) return Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, time); else return Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, time); }
public DateRecurrenceIterator createIterator(Date now) { RRule rrule = createRRule(); try { Log.d("RRULE", "Creating iterator for " + rrule.toIcal()); if (now.before(startDate.getTime())) { now = startDate.getTime(); } Calendar c = Calendar.getInstance(); c.setTime(startDate.getTime()); // c.set(Calendar.HOUR_OF_DAY, startDate.get(Calendar.HOUR_OF_DAY)); // c.set(Calendar.MINUTE, startDate.get(Calendar.MINUTE)); // c.set(Calendar.SECOND, startDate.get(Calendar.SECOND)); c.set(Calendar.MILLISECOND, 0); return DateRecurrenceIterator.create(rrule, now, c.getTime()); } catch (ParseException e) { Log.w("RRULE", "Unable to create iterator for " + rrule.toIcal()); return DateRecurrenceIterator.empty(); } }
private static long handleWeeklyRepeatAfterComplete( RRule rrule, DateTime original, boolean hasDueTime) { List<WeekdayNum> byDay = rrule.getByDay(); long newDate = original.getMillis(); newDate += DateUtilities.ONE_WEEK * (rrule.getInterval() - 1); DateTime date = new DateTime(newDate); Collections.sort(byDay, weekdayCompare); WeekdayNum next = findNextWeekday(byDay, date); do { date = date.plusDays(1); } while (date.getDayOfWeek() != next.wday.javaDayNum); long time = date.getMillis(); if (hasDueTime) { return Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, time); } else { return Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, time); } }
@Override public Void visitString(Property<String> property, UpgradeVisitorContainer<?> data) { String value = data.cursor.getString(data.columnIndex); if (property == Task.RECURRENCE) { LegacyRepeatInfo repeatInfo = LegacyRepeatInfo.fromSingleField(data.cursor.getInt(data.columnIndex)); if (repeatInfo == null) data.model.setValue(property, ""); else { RRule rrule = repeatInfo.toRRule(); data.model.setValue(property, rrule.toIcal()); } } else { data.model.setValue(property, value); } Log.d( "upgrade", "wrote " + value + " to -> " + property + " of model id " + data.cursor.getLong(1)); return null; }
@Test public void testDueDateSpecificTime() throws ParseException { buildRRule(1, Frequency.DAILY); // test specific day & time long dayWithTime = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, newDate(2010, 8, 1, 10, 4, 0).getTime()); task.setValue(Task.DUE_DATE, dayWithTime); long nextDayWithTime = dayWithTime + DateUtilities.ONE_DAY; nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal(), false); assertDateTimeEquals(nextDayWithTime, nextDueDate); }
private static long handleMonthlyRepeat( DateTime original, DateValue startDateAsDV, boolean hasDueTime, RRule rrule) { if (original.isLastDayOfMonth()) { int interval = rrule.getInterval(); DateTime newDateTime = original.plusMonths(interval); long time = newDateTime.withDayOfMonth(newDateTime.getNumberOfDaysInMonth()).getMillis(); if (hasDueTime) { return Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, time); } else { return Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, time); } } else { return invokeRecurrence(rrule, original, startDateAsDV); } }
@Test public void testCompletionDateSpecificTime() throws ParseException { buildRRule(1, Frequency.DAILY); // test specific day & time long dayWithTime = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, newDate(2010, 8, 1, 10, 4, 0).getTime()); task.setValue(Task.DUE_DATE, dayWithTime); Date todayWithTime = newDate(); todayWithTime.setHours(10); todayWithTime.setMinutes(4); todayWithTime.setSeconds(1); long nextDayWithTimeLong = todayWithTime.getTime(); nextDayWithTimeLong += DateUtilities.ONE_DAY; nextDayWithTimeLong = nextDayWithTimeLong / 1000L * 1000; nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal(), true); assertDateTimeEquals(nextDayWithTimeLong, nextDueDate); }
/** Compute next due date */ public static long computeNextDueDate(Task task, String recurrence) throws ParseException { boolean repeatAfterCompletion = task.getFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION); RRule rrule = initRRule(recurrence); // initialize startDateAsDV Date original = setUpStartDate(task, repeatAfterCompletion, rrule.getFreq()); DateValue startDateAsDV = setUpStartDateAsDV(task, original); if (rrule.getFreq() == Frequency.HOURLY || rrule.getFreq() == Frequency.MINUTELY) return handleSubdayRepeat(original, rrule); else if (rrule.getFreq() == Frequency.WEEKLY && rrule.getByDay().size() > 0 && repeatAfterCompletion) return handleWeeklyRepeatAfterComplete(rrule, original, task.hasDueTime()); else return invokeRecurrence(rrule, original, startDateAsDV); }
/** Compute next due date */ public static long computeNextDueDate(Task task, String recurrence, boolean repeatAfterCompletion) throws ParseException { RRule rrule = initRRule(recurrence); // initialize startDateAsDV DateTime original = setUpStartDate(task, repeatAfterCompletion, rrule.getFreq()); DateValue startDateAsDV = setUpStartDateAsDV(task, original); if (rrule.getFreq() == Frequency.HOURLY || rrule.getFreq() == Frequency.MINUTELY) { return handleSubdayRepeat(original, rrule); } else if (rrule.getFreq() == Frequency.WEEKLY && rrule.getByDay().size() > 0 && repeatAfterCompletion) { return handleWeeklyRepeatAfterComplete(rrule, original, task.hasDueTime()); } else if (rrule.getFreq() == Frequency.MONTHLY) { return handleMonthlyRepeat(original, startDateAsDV, task.hasDueTime(), rrule); } else { return invokeRecurrence(rrule, original, startDateAsDV); } }
private void buildRRule(int interval, Frequency freq, Weekday... weekdays) { rrule.setInterval(interval); rrule.setFreq(freq); setRRuleDays(rrule, weekdays); }
private void setRRuleDays(RRule rrule, Weekday... weekdays) { ArrayList<WeekdayNum> days = new ArrayList<WeekdayNum>(); for (Weekday wd : weekdays) days.add(new WeekdayNum(0, wd)); rrule.setByDay(days); }
private void computeNextDueDate(boolean fromComplete) throws ParseException { nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal(), fromComplete); }