/** * Returns the the next date of this recurrence given a seed date and start date. The seed date * indicates the start of the fist occurrence of this recurrence. The start date is the starting * date to search for the next recurrence. Return null if there is no occurrence date after start * date. * * @return the next date in the recurrence series after startDate * @param seed the start date of this Recurrence's first instance * @param startDate the date to start the search */ public final Date getNextDate(final Date seed, final Date startDate) { final Calendar cal = Dates.getCalendarInstance(seed); cal.setTime(seed); // optimize the start time for selecting candidates // (only applicable where a COUNT is not specified) if (getCount() < 1) { final Calendar seededCal = (Calendar) cal.clone(); while (seededCal.getTime().before(startDate)) { cal.setTime(seededCal.getTime()); increment(seededCal); } } int invalidCandidateCount = 0; int noCandidateIncrementCount = 0; Date candidate = null; final Value value = seed instanceof DateTime ? Value.DATE_TIME : Value.DATE; while (true) { final Date candidateSeed = Dates.getInstance(cal.getTime(), value); if (getUntil() != null && candidate != null && candidate.after(getUntil())) { break; } if (getCount() > 0 && invalidCandidateCount >= getCount()) { break; } if (Value.DATE_TIME.equals(value)) { if (((DateTime) seed).isUtc()) { ((DateTime) candidateSeed).setUtc(true); } else { ((DateTime) candidateSeed).setTimeZone(((DateTime) seed).getTimeZone()); } } final DateList candidates = getCandidates(candidateSeed, value); if (!candidates.isEmpty()) { noCandidateIncrementCount = 0; // sort candidates for identifying when UNTIL date is exceeded.. Collections.sort(candidates); for (final Iterator<Date> i = candidates.iterator(); i.hasNext(); ) { candidate = i.next(); // don't count candidates that occur before the seed date.. if (!candidate.before(seed)) { // Candidate must be after startDate because // we want the NEXT occurrence if (!candidate.after(startDate)) { invalidCandidateCount++; } else if (getCount() > 0 && invalidCandidateCount >= getCount()) { break; } else if (!(getUntil() != null && candidate.after(getUntil()))) { return candidate; } } } } else { noCandidateIncrementCount++; if ((maxIncrementCount > 0) && (noCandidateIncrementCount > maxIncrementCount)) { break; } } increment(cal); } return null; }
/** * Returns a list of start dates in the specified period represented by this recur. This method * includes a base date argument, which indicates the start of the fist occurrence of this * recurrence. The base date is used to inject default values to return a set of dates in the * correct format. For example, if the search start date (start) is Wed, Mar 23, 12:19PM, but the * recurrence is Mon - Fri, 9:00AM - 5:00PM, the start dates returned should all be at 9:00AM, and * not 12:19PM. * * @return a list of dates represented by this recur instance * @param seed the start date of this Recurrence's first instance * @param periodStart the start of the period * @param periodEnd the end of the period * @param value the type of dates to generate (i.e. date/date-time) * @param maxCount limits the number of instances returned. Up to one years worth extra may be * returned. Less than 0 means no limit */ public final DateList getDates( final Date seed, final Date periodStart, final Date periodEnd, final Value value, final int maxCount) { final DateList dates = new DateList(value); if (seed instanceof DateTime) { if (((DateTime) seed).isUtc()) { dates.setUtc(true); } else { dates.setTimeZone(((DateTime) seed).getTimeZone()); } } final Calendar cal = Dates.getCalendarInstance(seed); cal.setTime(seed); // optimize the start time for selecting candidates // (only applicable where a COUNT is not specified) if (getCount() < 1) { final Calendar seededCal = (Calendar) cal.clone(); while (seededCal.getTime().before(periodStart)) { cal.setTime(seededCal.getTime()); increment(seededCal); } } int invalidCandidateCount = 0; int noCandidateIncrementCount = 0; Date candidate = null; while ((maxCount < 0) || (dates.size() < maxCount)) { final Date candidateSeed = Dates.getInstance(cal.getTime(), value); if (getUntil() != null && candidate != null && candidate.after(getUntil())) { break; } if (periodEnd != null && candidate != null && candidate.after(periodEnd)) { break; } if (getCount() >= 1 && (dates.size() + invalidCandidateCount) >= getCount()) { break; } // if (Value.DATE_TIME.equals(value)) { if (candidateSeed instanceof DateTime) { if (dates.isUtc()) { ((DateTime) candidateSeed).setUtc(true); } else { ((DateTime) candidateSeed).setTimeZone(dates.getTimeZone()); } } final DateList candidates = getCandidates(candidateSeed, value); if (!candidates.isEmpty()) { noCandidateIncrementCount = 0; // sort candidates for identifying when UNTIL date is exceeded.. Collections.sort(candidates); for (final Iterator<Date> i = candidates.iterator(); i.hasNext(); ) { candidate = i.next(); // don't count candidates that occur before the seed date.. if (!candidate.before(seed)) { // candidates exclusive of periodEnd.. if (candidate.before(periodStart) || !candidate.before(periodEnd)) { invalidCandidateCount++; } else if (getCount() >= 1 && (dates.size() + invalidCandidateCount) >= getCount()) { break; } else if (!(getUntil() != null && candidate.after(getUntil()))) { dates.add(candidate); } } } } else { noCandidateIncrementCount++; if ((maxIncrementCount > 0) && (noCandidateIncrementCount > maxIncrementCount)) { break; } } increment(cal); } // sort final list.. Collections.sort(dates); return dates; }