From d3578e539a89148697cd0570636a74384f2ae24a Mon Sep 17 00:00:00 2001 From: Sunik Kupfer Date: Mon, 9 Mar 2026 12:53:20 +0100 Subject: [PATCH 1/5] Update ICalendar.vAlarmToMin() --- .../at/bitfire/ical4android/ICalendar.kt | 49 +++++++------ .../at/bitfire/ical4android/ICalendarTest.kt | 73 ++++++++++--------- 2 files changed, 63 insertions(+), 59 deletions(-) diff --git a/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt b/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt index ff80ed45..464d42ca 100644 --- a/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt +++ b/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt @@ -14,10 +14,9 @@ import at.bitfire.synctools.icalendar.propertyListOf import at.bitfire.synctools.icalendar.validation.ICalPreprocessor import net.fortuna.ical4j.model.Calendar import net.fortuna.ical4j.model.ComponentList -import net.fortuna.ical4j.model.Date +import net.fortuna.ical4j.model.Parameter import net.fortuna.ical4j.model.Property import net.fortuna.ical4j.model.TemporalAdapter -import net.fortuna.ical4j.model.TemporalComparator import net.fortuna.ical4j.model.component.Daylight import net.fortuna.ical4j.model.component.Observance import net.fortuna.ical4j.model.component.Standard @@ -29,16 +28,18 @@ import net.fortuna.ical4j.model.property.DtStart import net.fortuna.ical4j.model.property.ProdId import net.fortuna.ical4j.model.property.RDate import net.fortuna.ical4j.model.property.RRule +import net.fortuna.ical4j.model.property.Trigger import net.fortuna.ical4j.validate.ValidationException import java.io.Reader +import java.time.Duration +import java.time.Period import java.time.ZonedDateTime import java.time.temporal.Temporal -import java.time.temporal.TemporalAccessor -import java.time.temporal.TemporalAdjuster import java.util.LinkedList import java.util.UUID import java.util.logging.Level import java.util.logging.Logger +import kotlin.jvm.optionals.getOrNull open class ICalendar { @@ -261,7 +262,7 @@ open class ICalendar { // misc. iCalendar helpers /** - * Calculates the minutes before/after an event/task a given alarm occurs. + * Calculates the minutes before/after an event/task to know whem given alarm occurs. * * @param alarm the alarm to calculate the minutes from * @param refStart reference `DTSTART` from the calendar component @@ -286,34 +287,34 @@ open class ICalendar { refDuration: net.fortuna.ical4j.model.property.Duration?, allowRelEnd: Boolean ): Pair? { - val trigger = alarm.trigger ?: return null + val trigger = alarm.getProperty(Property.TRIGGER).getOrNull() ?: return null - TODO("ical4j 4.x") // Note: big method – maybe split? - /*val minutes: Int // minutes before/after the event - var related = trigger.getParameter(Parameter.RELATED) ?: Related.START + val minutes: Int // minutes before/after the event + var related: Related = trigger.getParameter(Parameter.RELATED).getOrNull() ?: Related.START - // event/task start time - val start: java.util.Date? = refStart?.date - var end: java.util.Date? = refEnd?.date + // event/task start/end time + val start: Temporal? = refStart?.date + var end: Temporal? = refEnd?.date // event/task end time - if (end == null && start != null) { - val duration = refDuration?.duration - if (duration != null) - end = java.util.Date.from(start.toInstant() + duration) - } + if (end == null && start != null) + end = when (val refDur = refDuration?.duration) { + is Duration -> start + refDur + is Period -> start + Duration.between(start, start + refDur) + else -> null + } // event/task duration val duration: Duration? = if (start != null && end != null) - Duration.between(start.toInstant(), end.toInstant()) + Duration.between(start, end) else null val triggerDur = trigger.duration - val triggerTime = trigger.dateTime + val triggerTime = trigger.date if (triggerDur != null) { // TRIGGER value is a DURATION. Important: @@ -323,9 +324,11 @@ open class ICalendar { var millisBefore = when (triggerDur) { is Duration -> -triggerDur.toMillis() - is Period -> // TODO: Take time zones into account (will probably be possible with ical4j 4.x). + is Period -> { + // TODO: Take time zones into account (will probably be possible with ical4j 4.x). // For instance, an alarm one day before the DST change should be 23/25 hours before the event. - -triggerDur.days.toLong()*24*3600000 // months and years are not used in DURATION values; weeks are calculated to days + -Duration.ofDays(triggerDur.days.toLong()).toMillis() // months and years are not used in DURATION values; weeks are calculated to days + } else -> throw AssertionError("triggerDur must be Duration or Period") } @@ -343,14 +346,14 @@ open class ICalendar { } else if (triggerTime != null && start != null) { // TRIGGER value is a DATE-TIME, calculate minutes from start time related = Related.START - minutes = Duration.between(triggerTime.toInstant(), start.toInstant()).toMinutes().toInt() + minutes = Duration.between(triggerTime, start).toMinutes().toInt() } else { logger.log(Level.WARNING, "VALARM TRIGGER type is not DURATION or DATE-TIME (requires event DTSTART for Android), ignoring alarm", alarm) return null } - return Pair(related, minutes)*/ + return Pair(related, minutes) } } diff --git a/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt b/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt index f6c40a77..b5f83958 100644 --- a/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt +++ b/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt @@ -8,17 +8,17 @@ package at.bitfire.ical4android import net.fortuna.ical4j.data.CalendarBuilder import net.fortuna.ical4j.model.Component -import net.fortuna.ical4j.model.DateTime -import net.fortuna.ical4j.model.Property +import net.fortuna.ical4j.model.Property.TRIGGER import net.fortuna.ical4j.model.TimeZone import net.fortuna.ical4j.model.TimeZoneRegistryFactory import net.fortuna.ical4j.model.component.VAlarm import net.fortuna.ical4j.model.component.VTimeZone import net.fortuna.ical4j.model.parameter.Related -import net.fortuna.ical4j.model.property.Color import net.fortuna.ical4j.model.property.DtEnd import net.fortuna.ical4j.model.property.DtStart import net.fortuna.ical4j.model.property.Due +import net.fortuna.ical4j.model.property.Duration +import net.fortuna.ical4j.model.property.Trigger import net.fortuna.ical4j.util.TimeZones import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull @@ -27,8 +27,10 @@ import org.junit.Ignore import org.junit.Test import java.io.StringReader import java.time.LocalDateTime +import java.time.Period import java.time.ZonedDateTime -import java.util.Date +import java.time.temporal.Temporal +import kotlin.jvm.optionals.getOrNull class ICalendarTest { @@ -47,7 +49,7 @@ class ICalendarTest { private val vtzMogadishu = readTimeZone("Mogadishu.ics") // current time stamp - private val currentTime = Date().time + private val currentTime = ZonedDateTime.now() private fun readTimeZone(fileName: String): VTimeZone { @@ -58,7 +60,6 @@ class ICalendarTest { } } - @Ignore("ical4j 4.x") @Test fun testFromReader_calendarProperties() { val calendar = ICalendar.fromReader( @@ -234,12 +235,12 @@ class ICalendarTest { } - /*@Test + @Test fun testVAlarmToMin_TriggerDuration_Negative() { // TRIGGER;REL=START:-P1DT1H1M29S val (ref, min) = ICalendar.vAlarmToMin( - VAlarm(Duration.parse("-P1DT1H1M29S")), - DtStart(), null, null, false + VAlarm(Duration("-P1DT1H1M29S").duration), + DtStart(), null, null, false )!! assertEquals(Related.START, ref) assertEquals(60 * 24 + 60 + 1, min) @@ -249,8 +250,8 @@ class ICalendarTest { fun testVAlarmToMin_TriggerDuration_OnlySeconds() { // TRIGGER;REL=START:-PT3600S val (ref, min) = ICalendar.vAlarmToMin( - VAlarm(Duration.parse("-PT3600S")), - DtStart(), null, null, false + VAlarm(Duration("-PT3600S").duration), + DtStart(), null, null, false )!! assertEquals(Related.START, ref) assertEquals(60, min) @@ -260,8 +261,8 @@ class ICalendarTest { fun testVAlarmToMin_TriggerDuration_Positive() { // TRIGGER;REL=START:P1DT1H1M30S (alarm *after* start) val (ref, min) = ICalendar.vAlarmToMin( - VAlarm(Duration.parse("P1DT1H1M30S")), - DtStart(), null, null, false + VAlarm(Duration("P1DT1H1M30S").duration), + DtStart(), null, null, false )!! assertEquals(Related.START, ref) assertEquals(-(60 * 24 + 60 + 1), min) @@ -270,9 +271,9 @@ class ICalendarTest { @Test fun testVAlarmToMin_TriggerDuration_RelEndAllowed() { // TRIGGER;REL=END:-P1DT1H1M30S (caller accepts Related.END) - val alarm = VAlarm(Duration.parse("-P1DT1H1M30S")) - alarm.trigger.parameters.add(Related.END) - val (ref, min) = ICalendar.vAlarmToMin(alarm, DtStart(), null, null, true)!! + val alarm = VAlarm(Duration("-P1DT1H1M30S").duration) + alarm.getProperty(TRIGGER).getOrNull()?.add(Related.END) + val (ref, min) = ICalendar.vAlarmToMin(alarm, DtStart(), null, null, true)!! assertEquals(Related.END, ref) assertEquals(60 * 24 + 60 + 1, min) } @@ -280,12 +281,12 @@ class ICalendarTest { @Test fun testVAlarmToMin_TriggerDuration_RelEndNotAllowed() { // event with TRIGGER;REL=END:-PT30S (caller doesn't accept Related.END) - val alarm = VAlarm(Duration.parse("-PT65S")) - alarm.trigger.parameters.add(Related.END) + val alarm = VAlarm(Duration("-PT65S").duration) + alarm.getProperty(TRIGGER).getOrNull()?.add(Related.END) val (ref, min) = ICalendar.vAlarmToMin( alarm, - DtStart(DateTime(currentTime)), - DtEnd(DateTime(currentTime + 180 * 1000)), // 180 sec later + DtStart(currentTime), + DtEnd(currentTime.plusSeconds(180)), // 180 sec later null, false )!! @@ -297,40 +298,40 @@ class ICalendarTest { @Test fun testVAlarmToMin_TriggerDuration_RelEndNotAllowed_NoDtStart() { // event with TRIGGER;REL=END:-PT30S (caller doesn't accept Related.END) - val alarm = VAlarm(Duration.parse("-PT65S")) - alarm.trigger.parameters.add(Related.END) - assertNull(ICalendar.vAlarmToMin(alarm, DtStart(), DtEnd(DateTime(currentTime)), null, false)) + val alarm = VAlarm(Duration("-PT65S").duration) + alarm.getProperty(TRIGGER).getOrNull()?.add(Related.END) + assertNull(ICalendar.vAlarmToMin(alarm, DtStart(), DtEnd(currentTime), null, false)) } @Test fun testVAlarmToMin_TriggerDuration_RelEndNotAllowed_NoDuration() { // event with TRIGGER;REL=END:-PT30S (caller doesn't accept Related.END) - val alarm = VAlarm(Duration.parse("-PT65S")) - alarm.trigger.parameters.add(Related.END) - assertNull(ICalendar.vAlarmToMin(alarm, DtStart(DateTime(currentTime)), null, null, false)) + val alarm = VAlarm(Duration("-PT65S").duration) + alarm.getProperty(TRIGGER).getOrNull()?.add(Related.END) + assertNull(ICalendar.vAlarmToMin(alarm, DtStart(currentTime), null, null, false)) } @Test fun testVAlarmToMin_TriggerDuration_RelEndNotAllowed_AfterEnd() { // task with TRIGGER;REL=END:-P1DT1H1M30S (caller doesn't accept Related.END; alarm *after* end) - val alarm = VAlarm(Duration.parse("P1DT1H1M30S")) - alarm.trigger.parameters.add(Related.END) + val alarm = VAlarm(Duration("P1DT1H1M30S").duration) + alarm.getProperty(TRIGGER).getOrNull()?.add(Related.END) val (ref, min) = ICalendar.vAlarmToMin( alarm, - DtStart(DateTime(currentTime)), - Due(DateTime(currentTime + 90 * 1000)), // 90 sec (should be rounded down to 1 min) later + DtStart(currentTime), + Due(currentTime.plusSeconds(90)), // 90 sec (should be rounded down to 1 min) later null, false )!! assertEquals(Related.START, ref) - assertEquals(-(60 * 24 + 60 + 1 + 1) *//* duration of event: *//* - 1, min) + assertEquals(-(60 * 24 + 60 + 1 + 1) /* duration of event: */ - 1, min) } @Test fun testVAlarm_TriggerPeriod() { val (ref, min) = ICalendar.vAlarmToMin( VAlarm(Period.parse("-P1W1D")), - DtStart(net.fortuna.ical4j.model.Date(currentTime)), null, null, + DtStart(currentTime), null, null, false )!! assertEquals(Related.START, ref) @@ -340,12 +341,12 @@ class ICalendarTest { @Test fun testVAlarm_TriggerAbsoluteValue() { // TRIGGER;VALUE=DATE-TIME: - val alarm = VAlarm(DateTime(currentTime - 89 * 1000)) // 89 sec (should be cut off to 1 min) before event - alarm.trigger.parameters.add(Related.END) // not useful for DATE-TIME values, should be ignored - val (ref, min) = ICalendar.vAlarmToMin(alarm, DtStart(DateTime(currentTime)), null, null, false)!! + val alarm = VAlarm(currentTime.minusSeconds(89).toInstant()) // 89 sec (should be cut off to 1 min) before event + alarm.getProperty(TRIGGER).getOrNull()?.add(Related.END) // not useful for DATE-TIME values, should be ignored + val (ref, min) = ICalendar.vAlarmToMin(alarm, DtStart(currentTime), null, null, false)!! assertEquals(Related.START, ref) assertEquals(1, min) - }*/ + } // TODO Note: can we use the following now when we have ical4j 4.x? From e1298692d61c1600e81e0f3d9648cf8968b6500c Mon Sep 17 00:00:00 2001 From: Sunik Kupfer Date: Mon, 9 Mar 2026 14:04:27 +0100 Subject: [PATCH 2/5] Update ICalendar.timezoneDefToTzId() --- .../main/kotlin/at/bitfire/ical4android/ICalendar.kt | 10 ++++++---- .../kotlin/at/bitfire/ical4android/ICalendarTest.kt | 3 +-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt b/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt index 464d42ca..141a463f 100644 --- a/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt +++ b/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt @@ -12,6 +12,8 @@ import at.bitfire.synctools.exception.InvalidICalendarException import at.bitfire.synctools.icalendar.ICalendarParser import at.bitfire.synctools.icalendar.propertyListOf import at.bitfire.synctools.icalendar.validation.ICalPreprocessor +import net.fortuna.ical4j.data.CalendarBuilder +import net.fortuna.ical4j.data.ParserException import net.fortuna.ical4j.model.Calendar import net.fortuna.ical4j.model.ComponentList import net.fortuna.ical4j.model.Parameter @@ -31,6 +33,7 @@ import net.fortuna.ical4j.model.property.RRule import net.fortuna.ical4j.model.property.Trigger import net.fortuna.ical4j.validate.ValidationException import java.io.Reader +import java.io.StringReader import java.time.Duration import java.time.Period import java.time.ZonedDateTime @@ -224,15 +227,14 @@ open class ICalendar { * @return time zone id (TZID) if VTIMEZONE contains a TZID, null otherwise */ fun timezoneDefToTzId(timezoneDef: String): String? { - TODO("ical4j 4.x") - /*try { + try { val builder = CalendarBuilder() val cal = builder.build(StringReader(timezoneDef)) - val timezone = cal.getComponent(VTimeZone.VTIMEZONE) as VTimeZone? + val timezone = cal.getComponent(VTimeZone.VTIMEZONE).getOrNull() timezone?.timeZoneId?.let { return it.value } } catch (e: ParserException) { logger.log(Level.SEVERE, "Can't understand time zone definition", e) - }*/ + } return null } diff --git a/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt b/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt index b5f83958..e3c1876d 100644 --- a/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt +++ b/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt @@ -60,6 +60,7 @@ class ICalendarTest { } } + @Ignore("ical4j 4.x") @Test fun testFromReader_calendarProperties() { val calendar = ICalendar.fromReader( @@ -186,7 +187,6 @@ class ICalendarTest { } - @Ignore("ical4j 4.x") @Test fun testTimezoneDefToTzId_Valid() { assertEquals( @@ -217,7 +217,6 @@ class ICalendarTest { ) } - @Ignore("ical4j 4.x") @Test fun testTimezoneDefToTzId_Invalid() { // invalid time zone From d35ad4d374c853457e4e4805e1bb6214aea87c87 Mon Sep 17 00:00:00 2001 From: Sunik Kupfer Date: Mon, 9 Mar 2026 14:45:43 +0100 Subject: [PATCH 3/5] Update ICalendar.fromReader() # Conflicts: # lib/src/main/kotlin/at/bitfire/synctools/icalendar/validation/ICalPreprocessor.kt --- .../kotlin/at/bitfire/ical4android/ICalendar.kt | 10 +++++----- .../kotlin/at/bitfire/ical4android/ICalendarTest.kt | 13 ++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt b/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt index 141a463f..0cb57243 100644 --- a/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt +++ b/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt @@ -25,6 +25,7 @@ import net.fortuna.ical4j.model.component.Standard import net.fortuna.ical4j.model.component.VAlarm import net.fortuna.ical4j.model.component.VTimeZone import net.fortuna.ical4j.model.parameter.Related +import net.fortuna.ical4j.model.property.Color import net.fortuna.ical4j.model.property.DateProperty import net.fortuna.ical4j.model.property.DtStart import net.fortuna.ical4j.model.property.ProdId @@ -105,17 +106,16 @@ open class ICalendar { // fill calendar properties properties?.let { - TODO("ical4j 4.x") - /*calendar.getProperty(CALENDAR_NAME)?.let { calName -> + calendar.getProperty(CALENDAR_NAME).getOrNull()?.let { calName -> properties[CALENDAR_NAME] = calName.value } - calendar.getProperty(Color.PROPERTY_NAME)?.let { calColor -> + calendar.getProperty(Color.PROPERTY_NAME).getOrNull()?.let { calColor -> properties[Color.PROPERTY_NAME] = calColor.value } - calendar.getProperty(CALENDAR_COLOR)?.let { calColor -> + calendar.getProperty(CALENDAR_COLOR).getOrNull()?.let { calColor -> properties[CALENDAR_COLOR] = calColor.value - }*/ + } } return calendar diff --git a/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt b/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt index e3c1876d..6ea598bf 100644 --- a/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt +++ b/lib/src/test/kotlin/at/bitfire/ical4android/ICalendarTest.kt @@ -8,12 +8,14 @@ package at.bitfire.ical4android import net.fortuna.ical4j.data.CalendarBuilder import net.fortuna.ical4j.model.Component +import net.fortuna.ical4j.model.Property import net.fortuna.ical4j.model.Property.TRIGGER import net.fortuna.ical4j.model.TimeZone import net.fortuna.ical4j.model.TimeZoneRegistryFactory import net.fortuna.ical4j.model.component.VAlarm import net.fortuna.ical4j.model.component.VTimeZone import net.fortuna.ical4j.model.parameter.Related +import net.fortuna.ical4j.model.property.Color import net.fortuna.ical4j.model.property.DtEnd import net.fortuna.ical4j.model.property.DtStart import net.fortuna.ical4j.model.property.Due @@ -23,7 +25,6 @@ import net.fortuna.ical4j.util.TimeZones import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull -import org.junit.Ignore import org.junit.Test import java.io.StringReader import java.time.LocalDateTime @@ -60,7 +61,7 @@ class ICalendarTest { } } - @Ignore("ical4j 4.x") + @Test fun testFromReader_calendarProperties() { val calendar = ICalendar.fromReader( @@ -75,13 +76,11 @@ class ICalendarTest { "END:VCALENDAR" ) ) - TODO("ical4j 4.x") - /*assertEquals("Some Calendar", calendar.getProperty(ICalendar.CALENDAR_NAME).value) - assertEquals("darkred", calendar.getProperty(Color.PROPERTY_NAME).value) - assertEquals("#123456", calendar.getProperty(ICalendar.CALENDAR_COLOR).value)*/ + assertEquals("Some Calendar", calendar.getProperty(ICalendar.CALENDAR_NAME).getOrNull()?.value) + assertEquals("darkred", calendar.getProperty(Color.PROPERTY_NAME).getOrNull()?.value) + assertEquals("#123456", calendar.getProperty(ICalendar.CALENDAR_COLOR).getOrNull()?.value) } - @Ignore("ical4j 4.x") @Test fun testFromReader_invalidProperty() { // The GEO property is invalid and should be ignored. From 35be778f315fe7346a5cf40ba8ff507a01ca34b4 Mon Sep 17 00:00:00 2001 From: Sunik Kupfer Date: Tue, 10 Mar 2026 08:59:45 +0100 Subject: [PATCH 4/5] Remove CreatedPropertyRule  Conflicts:  lib/src/main/kotlin/at/bitfire/synctools/icalendar/validation/ICalPreprocessor.kt --- .../bitfire/synctools/icalendar/validation/ICalPreprocessor.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/main/kotlin/at/bitfire/synctools/icalendar/validation/ICalPreprocessor.kt b/lib/src/main/kotlin/at/bitfire/synctools/icalendar/validation/ICalPreprocessor.kt index b7ec7ade..d030c782 100644 --- a/lib/src/main/kotlin/at/bitfire/synctools/icalendar/validation/ICalPreprocessor.kt +++ b/lib/src/main/kotlin/at/bitfire/synctools/icalendar/validation/ICalPreprocessor.kt @@ -10,6 +10,7 @@ import androidx.annotation.VisibleForTesting import com.google.common.io.CharSource import net.fortuna.ical4j.model.Calendar import net.fortuna.ical4j.model.Property +import net.fortuna.ical4j.model.component.CalendarComponent import net.fortuna.ical4j.transform.compliance.DateListPropertyRule import net.fortuna.ical4j.transform.compliance.DatePropertyRule import net.fortuna.ical4j.transform.compliance.Rfc5545PropertyRule From c8293c8f819dc429ce2e3e921e66c530866450db Mon Sep 17 00:00:00 2001 From: Sunik Kupfer Date: Tue, 10 Mar 2026 09:08:11 +0100 Subject: [PATCH 5/5] Typo --- lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt b/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt index 0cb57243..dcd7ffd4 100644 --- a/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt +++ b/lib/src/main/kotlin/at/bitfire/ical4android/ICalendar.kt @@ -264,7 +264,7 @@ open class ICalendar { // misc. iCalendar helpers /** - * Calculates the minutes before/after an event/task to know whem given alarm occurs. + * Calculates the minutes before/after an event/task to know when a given alarm occurs. * * @param alarm the alarm to calculate the minutes from * @param refStart reference `DTSTART` from the calendar component