diff --git a/bundles/org.openhab.binding.icalendar/pom.xml b/bundles/org.openhab.binding.icalendar/pom.xml
index 0c12afd98..768f07224 100644
--- a/bundles/org.openhab.binding.icalendar/pom.xml
+++ b/bundles/org.openhab.binding.icalendar/pom.xml
@@ -17,12 +17,12 @@
net.sf.biweekly
biweekly
- 0.6.4
+ 0.6.6
compile
com.fasterxml.jackson.core
- *
+ jackson-databind
@@ -39,12 +39,6 @@
${jackson.version}
compile
-
- com.fasterxml.jackson.core
- jackson-annotations
- ${jackson.version}
- compile
-
com.fasterxml.jackson.core
jackson-databind
diff --git a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java
index 61d2f9a25..d38e9e445 100644
--- a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java
+++ b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java
@@ -88,55 +88,14 @@ class BiweeklyPresentableCalendar extends AbstractPresentableCalendar {
@Override
public List getJustBegunEvents(Instant frameBegin, Instant frameEnd) {
- final List eventList = new ArrayList<>();
- // process all the events in the iCalendar
- for (final VEvent event : usedCalendar.getEvents()) {
- // iterate over all begin dates
- final DateIterator begDates = getRecurredEventDateIterator(event);
- while (begDates.hasNext()) {
- final Instant begInst = begDates.next().toInstant();
- if (begInst.isBefore(frameBegin)) {
- continue;
- } else if (begInst.isAfter(frameEnd)) {
- break;
- }
- // fall through => means we are within the time frame
- Duration duration = getEventLength(event);
- if (duration == null) {
- duration = Duration.ofMinutes(1);
- }
- eventList.add(new VEventWPeriod(event, begInst, begInst.plus(duration)).toEvent());
- break;
- }
- }
- return eventList;
+ return this.getVEventWPeriodsBetween(frameBegin, frameEnd, 0).stream().map(e -> e.toEvent())
+ .collect(Collectors.toList());
}
@Override
public List getJustEndedEvents(Instant frameBegin, Instant frameEnd) {
- final List eventList = new ArrayList<>();
- // process all the events in the iCalendar
- for (final VEvent event : usedCalendar.getEvents()) {
- final Duration duration = getEventLength(event);
- if (duration == null) {
- continue;
- }
- // iterate over all begin dates
- final DateIterator begDates = getRecurredEventDateIterator(event);
- while (begDates.hasNext()) {
- final Instant begInst = begDates.next().toInstant();
- final Instant endInst = begInst.plus(duration);
- if (endInst.isBefore(frameBegin)) {
- continue;
- } else if (endInst.isAfter(frameEnd)) {
- break;
- }
- // fall through => means we are within the time frame
- eventList.add(new VEventWPeriod(event, begInst, endInst).toEvent());
- break;
- }
- }
- return eventList;
+ return this.getVEventWPeriodsBetween(frameBegin, frameEnd, 0, true).stream().map(e -> e.toEvent())
+ .collect(Collectors.toList());
}
@Override
@@ -247,6 +206,20 @@ class BiweeklyPresentableCalendar extends AbstractPresentableCalendar {
* @return All events which begin in the time frame.
*/
private List getVEventWPeriodsBetween(Instant frameBegin, Instant frameEnd, int maximumPerSeries) {
+ return this.getVEventWPeriodsBetween(frameBegin, frameEnd, maximumPerSeries, false);
+ }
+
+ /**
+ * Finds events which begin in the given frame by end time and date
+ *
+ * @param frameBegin Begin of the frame where to search events.
+ * @param frameEnd End of the time frame where to search events. The Instant is inclusive when searchByEnd is true.
+ * @param maximumPerSeries Limit the results per series. Set to 0 for no limit.
+ * @param searchByEnd Whether to search by begin of the event or by end.
+ * @return All events which begin in the time frame.
+ */
+ private List getVEventWPeriodsBetween(Instant frameBegin, Instant frameEnd, int maximumPerSeries,
+ boolean searchByEnd) {
final List positiveEvents = new ArrayList<>();
final List negativeEvents = new ArrayList<>();
classifyEvents(positiveEvents, negativeEvents);
@@ -254,16 +227,22 @@ class BiweeklyPresentableCalendar extends AbstractPresentableCalendar {
final List eventList = new ArrayList<>();
for (final VEvent positiveEvent : positiveEvents) {
final DateIterator positiveBeginDates = getRecurredEventDateIterator(positiveEvent);
- positiveBeginDates.advanceTo(Date.from(frameBegin));
+ Duration duration = getEventLength(positiveEvent);
+ if (duration == null) {
+ duration = Duration.ZERO;
+ }
+ positiveBeginDates.advanceTo(Date.from(frameBegin.minus(searchByEnd ? duration : Duration.ZERO)));
int foundInSeries = 0;
while (positiveBeginDates.hasNext()) {
final Instant begInst = positiveBeginDates.next().toInstant();
- if (begInst.isAfter(frameEnd) || begInst.equals(frameEnd)) {
+ if ((!searchByEnd && (begInst.isAfter(frameEnd) || begInst.equals(frameEnd)))
+ || (searchByEnd && begInst.plus(duration).isAfter(frameEnd))) {
break;
}
- Duration duration = getEventLength(positiveEvent);
- if (duration == null) {
- duration = Duration.ZERO;
+ // biweekly is not as precise as java.time. An exact check is required.
+ if ((!searchByEnd && begInst.isBefore(frameBegin))
+ || (searchByEnd && begInst.plus(duration).isBefore(frameBegin))) {
+ continue;
}
final VEventWPeriod resultingVEWP = new VEventWPeriod(positiveEvent, begInst, begInst.plus(duration));
diff --git a/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java b/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java
index 7c60c4fb6..c4857336c 100644
--- a/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java
+++ b/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java
@@ -49,6 +49,7 @@ public class BiweeklyPresentableCalendarTest {
private AbstractPresentableCalendar calendar3;
private AbstractPresentableCalendar calendar_issue9647;
private AbstractPresentableCalendar calendar_issue10808;
+ private AbstractPresentableCalendar calendar_issue11084;
@BeforeEach
public void setUp() throws IOException, CalendarException {
@@ -59,6 +60,8 @@ public class BiweeklyPresentableCalendarTest {
new FileInputStream("src/test/resources/test-issue9647.ics"));
calendar_issue10808 = new BiweeklyPresentableCalendar(
new FileInputStream("src/test/resources/test-issue10808.ics"));
+ calendar_issue11084 = new BiweeklyPresentableCalendar(
+ new FileInputStream("src/test/resources/test-issue11084.ics"));
}
/**
@@ -132,6 +135,13 @@ public class BiweeklyPresentableCalendarTest {
Event currentEvent4 = calendar_issue10808.getCurrentEvent(Instant.parse("2021-06-05T17:18:05Z"));
assertNotNull(currentEvent4);
assertTrue("Test event 1".contentEquals(currentEvent4.title));
+
+ Event currentEvent5 = calendar_issue11084.getCurrentEvent(Instant.parse("2021-08-16T16:30:05Z"));
+ assertNull(currentEvent5);
+
+ Event currentEvent6 = calendar_issue11084.getCurrentEvent(Instant.parse("2021-08-16T16:45:05Z"));
+ assertNotNull(currentEvent6);
+ assertTrue("TEST_REPEATING_EVENT_3".contentEquals(currentEvent6.title));
}
/**
@@ -563,6 +573,17 @@ public class BiweeklyPresentableCalendarTest {
cmd7 = cmdTags.get(7).getCommand();
assertNotNull(cmd7);
assertEquals(DecimalType.class, cmd7.getClass());
+
+ // issue 11084: Command tags from moved events are also executed
+ List events2 = calendar_issue11084.getJustBegunEvents(Instant.parse("2021-08-16T16:29:55Z"),
+ Instant.parse("2021-08-16T17:00:05Z"));
+ assertEquals(1, events2.size());
+ assertEquals(Instant.parse("2021-08-16T16:45:00Z"), events2.get(0).start);
+
+ List events3 = calendar_issue11084.getJustEndedEvents(Instant.parse("2021-08-16T16:29:55Z"),
+ Instant.parse("2021-08-16T17:00:05Z"));
+ assertEquals(1, events3.size());
+ assertEquals(Instant.parse("2021-08-16T17:00:00Z"), events3.get(0).end);
}
@SuppressWarnings("null")
@@ -621,5 +642,9 @@ public class BiweeklyPresentableCalendarTest {
LocalDate.parse("2021-01-04").atStartOfDay(ZoneId.systemDefault()).toInstant(),
LocalDate.parse("2021-01-05").atStartOfDay(ZoneId.systemDefault()).toInstant(), null, 3);
assertArrayEquals(expectedFilteredEvents8, realFilteredEvents8.toArray(new Event[] {}));
+
+ List realFilteredEvents9 = calendar_issue11084.getFilteredEventsBetween(
+ Instant.parse("2021-08-16T16:45:00.123456Z"), Instant.parse("2021-08-16T16:46:00.768643Z"), null, 3);
+ assertEquals(0, realFilteredEvents9.size());
}
}
diff --git a/bundles/org.openhab.binding.icalendar/src/test/resources/test-issue11084.ics b/bundles/org.openhab.binding.icalendar/src/test/resources/test-issue11084.ics
new file mode 100644
index 000000000..38c208b09
--- /dev/null
+++ b/bundles/org.openhab.binding.icalendar/src/test/resources/test-issue11084.ics
@@ -0,0 +1,56 @@
+BEGIN:VCALENDAR
+PRODID:-//Google Inc//Google Calendar 70.9054//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:PUBLISH
+X-WR-CALNAME:ohtest
+X-WR-TIMEZONE:UTC
+BEGIN:VTIMEZONE
+TZID:Europe/Brussels
+X-LIC-LOCATION:Europe/Brussels
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+TZNAME:CEST
+DTSTART:19700329T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+TZNAME:CET
+DTSTART:19701025T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART;TZID=Europe/Brussels:20210816T184500
+DTEND;TZID=Europe/Brussels:20210816T190000
+DTSTAMP:20210816T174418Z
+UID:pseudo7346893o7r8328zheh@google.com
+RECURRENCE-ID;TZID=Europe/Brussels:20210816T183000
+CREATED:20210816T161602Z
+DESCRIPTION:BEGIN:E_Test_Cal:ON
+LAST-MODIFIED:20210816T162009Z
+LOCATION:
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:TEST_REPEATING_EVENT_3
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;TZID=Europe/Brussels:20210816T183000
+DTEND;TZID=Europe/Brussels:20210816T184500
+RRULE:FREQ=DAILY
+DTSTAMP:20210816T174418Z
+UID:pseudo7346893o7r8328zheh@google.com
+CREATED:20210816T161602Z
+DESCRIPTION:BEGIN:E_Test_Cal:ON
+LAST-MODIFIED:20210816T162009Z
+LOCATION:
+SEQUENCE:0
+STATUS:CONFIRMED
+SUMMARY:TEST_REPEATING_EVENT_3
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR