Skip to content

RecurrenceSetIterator.next() returns next date/times out of order. #61

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
AlexSolorio opened this issue Jul 9, 2019 · 3 comments
Closed

Comments

@AlexSolorio
Copy link

I discovered that when using two or more recurrence rules within a single RecurrenceSetIterator, calling next() on the iterator sometimes returns the next few date/times out of order.

A reproducible example is below, where we have two recurrence rules (every 5 hours and every day), both with a start time of 1/1/2019 at 12am. When fast-forwarding the iterator to 10pm, next() returns 1/2/2019 at 1am instead of 1/2/2019 at 12am. Calling next() again, however, returns 1/2/2019 at 12am, which is backwards in time from what it returned previously.

import org.junit.Test;

@Test
public void lib_recur_test() throws InvalidRecurrenceRuleException {

  // We are calculating for the next recurrence after 1/1/2019 at 10pm.
  ZoneId localTimeZone = ZoneId.of("UTC");
  final ZonedDateTime timeOfCalculation = ZonedDateTime.of(2019, 1, 1, 22, 0, 0, 0, localTimeZone);

  // Combine all Recurrence Rules into a RecurrenceSet
  RecurrenceSet ruleSet = new RecurrenceSet();
  ruleSet.addInstances(new RecurrenceRuleAdapter(new RecurrenceRule("FREQ=HOURLY;INTERVAL=5")));
  ruleSet.addInstances(new RecurrenceRuleAdapter(new RecurrenceRule("FREQ=DAILY;INTERVAL=1")));

  ZonedDateTime startDateTime = ZonedDateTime.of(2019, 1, 1, 0, 0, 0, 0, localTimeZone);
  long startTimeEpochMillis = startDateTime.toInstant().toEpochMilli();

  // Create an iterator using the RecurrenceSet
  RecurrenceSetIterator it = ruleSet.iterator(TimeZone.getTimeZone(localTimeZone), startTimeEpochMillis);

  // Fast forward to the time of calculation (1/1/2019 at 10pm).
  it.fastForward(timeOfCalculation.toInstant().toEpochMilli());

  if (it.hasNext()) {

    long nextRunTimeEpochMillis = it.next();

    // The next run time should be 1/2/2019 at 12am, due to the Daily recurrence rule defined above.
    ZonedDateTime expectedNextRunTime = ZonedDateTime.of(2019, 1, 2, 0, 0, 0, 0, localTimeZone);

    // However, the calculated next run time returns 1am.
    ZonedDateTime calculatedNextRunTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(nextRunTimeEpochMillis), localTimeZone);

    // Fails
    Assert.assertEquals(expectedNextRunTime, calculatedNextRunTime);
  }
}
@dmfs
Copy link
Owner

dmfs commented Jul 9, 2019

Does this only happen when you use fastForward?

@dmfs
Copy link
Owner

dmfs commented Jul 10, 2019

I've created a unit test which does the same thing without calling fastForward. As suspected this doesn't fail. So it appears to be the fastForward method which is broken. I'll have it fixed.

dmfs added a commit that referenced this issue Jul 11, 2019
The `fastForward` method didn't sort the instances array after fast forwarding all instance sources. The `fillInstanceCache` method, however, expects the array to be sorted by the next instance each source would return.
dmfs added a commit that referenced this issue Jul 11, 2019
The `fastForward` method didn't sort the instances array after fast forwarding all instance sources. The `fillInstanceCache` method, however, expects the array to be sorted by the next instance each source would return.
@dmfs dmfs closed this as completed in 068526a Jul 11, 2019
@dmfs
Copy link
Owner

dmfs commented Jul 11, 2019

fixed in 0.11.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants