Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/bitfireAT/ical4android.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRicki Hirner <hirner@bitfire.at>2022-09-08 22:56:19 +0300
committerGitHub <noreply@github.com>2022-09-08 22:56:19 +0300
commit2c31b0e8860efaa7ba5ec53b244b48463b9cd694 (patch)
tree3a559a15afde3ef83f336424b54694d47f952a2f
parent5a889101b1c88d359e4817f1b3dcfad7d7824fd5 (diff)
EventValidator: RRULE repairing inserts unwanted COUNT=-1 (#53)57-exception-when-unknown-timezone-in-calendar-provider
* EventValidator.sameTypeForDtStartAndRruleUntil: fix COUNT=-1 problem, add tests * Tests * EventValidator: always set UNTIL to UTC * Move util classes; add TimeZone.toZoneIdCompat() tests * Optimize imports
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/AndroidCalendarTest.kt4
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/AndroidEventTest.kt5
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/AndroidTaskTest.kt1
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/AndroidTimeZonesTest.kt1
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/AospTest.kt2
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/BatchOperationTest.kt2
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/EventTest.kt1
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/ICalendarTest.kt1
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/JtxCollectionTest.kt2
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/JtxICalObjectTest.kt2
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/TaskTest.kt1
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/impl/TestJtxCollection.kt2
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/util/AndroidTimeUtilsTest.kt (renamed from src/androidTest/java/at/bitfire/ical4android/AndroidTimeUtilsTest.kt)3
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/util/DateUtilsTest.kt (renamed from src/androidTest/java/at/bitfire/ical4android/DateUtilsTest.kt)2
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/util/MiscUtilsTest.kt (renamed from src/androidTest/java/at/bitfire/ical4android/MiscUtilsAndroidTest.kt)8
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/util/TimeApiExtensionsTest.kt (renamed from src/androidTest/java/at/bitfire/ical4android/TimeApiExtensionsTest.kt)57
-rw-r--r--src/androidTest/java/at/bitfire/ical4android/validation/EventValidatorTest.kt71
-rw-r--r--src/main/java/at/bitfire/ical4android/AndroidCalendar.kt4
-rw-r--r--src/main/java/at/bitfire/ical4android/AndroidEvent.kt16
-rw-r--r--src/main/java/at/bitfire/ical4android/AndroidTask.kt4
-rw-r--r--src/main/java/at/bitfire/ical4android/AndroidTaskList.kt4
-rw-r--r--src/main/java/at/bitfire/ical4android/Event.kt2
-rw-r--r--src/main/java/at/bitfire/ical4android/ICalendar.kt1
-rw-r--r--src/main/java/at/bitfire/ical4android/JtxCollection.kt2
-rw-r--r--src/main/java/at/bitfire/ical4android/JtxICalObject.kt2
-rw-r--r--src/main/java/at/bitfire/ical4android/Task.kt1
-rw-r--r--src/main/java/at/bitfire/ical4android/TaskProvider.kt2
-rw-r--r--src/main/java/at/bitfire/ical4android/util/AndroidTimeUtils.kt1
-rw-r--r--src/main/java/at/bitfire/ical4android/util/DateUtils.kt (renamed from src/main/java/at/bitfire/ical4android/DateUtils.kt)4
-rw-r--r--src/main/java/at/bitfire/ical4android/util/MiscUtils.kt (renamed from src/main/java/at/bitfire/ical4android/MiscUtils.kt)2
-rw-r--r--src/main/java/at/bitfire/ical4android/util/TimeApiExtensions.kt19
-rw-r--r--src/main/java/at/bitfire/ical4android/validation/EventValidator.kt57
-rw-r--r--src/test/java/at/bitfire/ical4android/MiscUtilsTest.kt1
33 files changed, 191 insertions, 96 deletions
diff --git a/src/androidTest/java/at/bitfire/ical4android/AndroidCalendarTest.kt b/src/androidTest/java/at/bitfire/ical4android/AndroidCalendarTest.kt
index a8ab2f4..dbd9c4c 100644
--- a/src/androidTest/java/at/bitfire/ical4android/AndroidCalendarTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/AndroidCalendarTest.kt
@@ -14,10 +14,10 @@ import android.provider.CalendarContract.Calendars
import android.provider.CalendarContract.Colors
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
-import at.bitfire.ical4android.MiscUtils.ContentProviderClientHelper.closeCompat
-import at.bitfire.ical4android.MiscUtils.UriHelper.asSyncAdapter
import at.bitfire.ical4android.impl.TestCalendar
import at.bitfire.ical4android.impl.TestEvent
+import at.bitfire.ical4android.util.MiscUtils.ContentProviderClientHelper.closeCompat
+import at.bitfire.ical4android.util.MiscUtils.UriHelper.asSyncAdapter
import net.fortuna.ical4j.model.property.DtEnd
import net.fortuna.ical4j.model.property.DtStart
import org.junit.*
diff --git a/src/androidTest/java/at/bitfire/ical4android/AndroidEventTest.kt b/src/androidTest/java/at/bitfire/ical4android/AndroidEventTest.kt
index c9ff0b2..556fa0b 100644
--- a/src/androidTest/java/at/bitfire/ical4android/AndroidEventTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/AndroidEventTest.kt
@@ -13,11 +13,12 @@ import android.net.Uri
import android.provider.CalendarContract.*
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.rule.GrantPermissionRule
-import at.bitfire.ical4android.MiscUtils.ContentProviderClientHelper.closeCompat
-import at.bitfire.ical4android.MiscUtils.UriHelper.asSyncAdapter
import at.bitfire.ical4android.impl.TestCalendar
import at.bitfire.ical4android.impl.TestEvent
import at.bitfire.ical4android.util.AndroidTimeUtils
+import at.bitfire.ical4android.util.DateUtils
+import at.bitfire.ical4android.util.MiscUtils.ContentProviderClientHelper.closeCompat
+import at.bitfire.ical4android.util.MiscUtils.UriHelper.asSyncAdapter
import net.fortuna.ical4j.model.*
import net.fortuna.ical4j.model.component.VAlarm
import net.fortuna.ical4j.model.parameter.*
diff --git a/src/androidTest/java/at/bitfire/ical4android/AndroidTaskTest.kt b/src/androidTest/java/at/bitfire/ical4android/AndroidTaskTest.kt
index c907439..61565cb 100644
--- a/src/androidTest/java/at/bitfire/ical4android/AndroidTaskTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/AndroidTaskTest.kt
@@ -12,6 +12,7 @@ import android.net.Uri
import androidx.test.filters.MediumTest
import at.bitfire.ical4android.impl.TestTask
import at.bitfire.ical4android.impl.TestTaskList
+import at.bitfire.ical4android.util.DateUtils
import net.fortuna.ical4j.model.Date
import net.fortuna.ical4j.model.DateList
import net.fortuna.ical4j.model.DateTime
diff --git a/src/androidTest/java/at/bitfire/ical4android/AndroidTimeZonesTest.kt b/src/androidTest/java/at/bitfire/ical4android/AndroidTimeZonesTest.kt
index d51c1ad..d6199ad 100644
--- a/src/androidTest/java/at/bitfire/ical4android/AndroidTimeZonesTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/AndroidTimeZonesTest.kt
@@ -4,6 +4,7 @@
package at.bitfire.ical4android
+import at.bitfire.ical4android.util.DateUtils
import org.junit.Assert
import org.junit.Assert.assertNotNull
import org.junit.Test
diff --git a/src/androidTest/java/at/bitfire/ical4android/AospTest.kt b/src/androidTest/java/at/bitfire/ical4android/AospTest.kt
index bf18803..c048f25 100644
--- a/src/androidTest/java/at/bitfire/ical4android/AospTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/AospTest.kt
@@ -12,7 +12,7 @@ import android.net.Uri
import android.provider.CalendarContract
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
-import at.bitfire.ical4android.MiscUtils.ContentProviderClientHelper.closeCompat
+import at.bitfire.ical4android.util.MiscUtils.ContentProviderClientHelper.closeCompat
import org.junit.After
import org.junit.Assert.assertNotNull
import org.junit.Before
diff --git a/src/androidTest/java/at/bitfire/ical4android/BatchOperationTest.kt b/src/androidTest/java/at/bitfire/ical4android/BatchOperationTest.kt
index 66310df..4ef3148 100644
--- a/src/androidTest/java/at/bitfire/ical4android/BatchOperationTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/BatchOperationTest.kt
@@ -13,9 +13,9 @@ import android.provider.CalendarContract
import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
-import at.bitfire.ical4android.MiscUtils.ContentProviderClientHelper.closeCompat
import at.bitfire.ical4android.impl.TestCalendar
import at.bitfire.ical4android.impl.TestEvent
+import at.bitfire.ical4android.util.MiscUtils.ContentProviderClientHelper.closeCompat
import net.fortuna.ical4j.model.property.Attendee
import net.fortuna.ical4j.model.property.DtEnd
import net.fortuna.ical4j.model.property.DtStart
diff --git a/src/androidTest/java/at/bitfire/ical4android/EventTest.kt b/src/androidTest/java/at/bitfire/ical4android/EventTest.kt
index f114bf3..e016b07 100644
--- a/src/androidTest/java/at/bitfire/ical4android/EventTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/EventTest.kt
@@ -4,6 +4,7 @@
package at.bitfire.ical4android
+import at.bitfire.ical4android.util.DateUtils
import net.fortuna.ical4j.model.Date
import net.fortuna.ical4j.model.DateTime
import net.fortuna.ical4j.model.Parameter
diff --git a/src/androidTest/java/at/bitfire/ical4android/ICalendarTest.kt b/src/androidTest/java/at/bitfire/ical4android/ICalendarTest.kt
index ee0b944..a62fb72 100644
--- a/src/androidTest/java/at/bitfire/ical4android/ICalendarTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/ICalendarTest.kt
@@ -4,6 +4,7 @@
package at.bitfire.ical4android
+import at.bitfire.ical4android.util.DateUtils
import net.fortuna.ical4j.data.CalendarBuilder
import net.fortuna.ical4j.model.Component
import net.fortuna.ical4j.model.Date
diff --git a/src/androidTest/java/at/bitfire/ical4android/JtxCollectionTest.kt b/src/androidTest/java/at/bitfire/ical4android/JtxCollectionTest.kt
index 29b5157..3e9f886 100644
--- a/src/androidTest/java/at/bitfire/ical4android/JtxCollectionTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/JtxCollectionTest.kt
@@ -9,8 +9,8 @@ import android.content.ContentProviderClient
import android.content.ContentValues
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
-import at.bitfire.ical4android.MiscUtils.ContentProviderClientHelper.closeCompat
import at.bitfire.ical4android.impl.TestJtxCollection
+import at.bitfire.ical4android.util.MiscUtils.ContentProviderClientHelper.closeCompat
import at.techbee.jtx.JtxContract
import at.techbee.jtx.JtxContract.asSyncAdapter
import junit.framework.TestCase.*
diff --git a/src/androidTest/java/at/bitfire/ical4android/JtxICalObjectTest.kt b/src/androidTest/java/at/bitfire/ical4android/JtxICalObjectTest.kt
index f82c07d..e0cb10a 100644
--- a/src/androidTest/java/at/bitfire/ical4android/JtxICalObjectTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/JtxICalObjectTest.kt
@@ -11,8 +11,8 @@ import android.database.DatabaseUtils
import android.os.ParcelFileDescriptor
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
-import at.bitfire.ical4android.MiscUtils.ContentProviderClientHelper.closeCompat
import at.bitfire.ical4android.impl.TestJtxCollection
+import at.bitfire.ical4android.util.MiscUtils.ContentProviderClientHelper.closeCompat
import at.techbee.jtx.JtxContract
import at.techbee.jtx.JtxContract.JtxICalObject
import at.techbee.jtx.JtxContract.JtxICalObject.Component
diff --git a/src/androidTest/java/at/bitfire/ical4android/TaskTest.kt b/src/androidTest/java/at/bitfire/ical4android/TaskTest.kt
index cbe0bcc..f9f72af 100644
--- a/src/androidTest/java/at/bitfire/ical4android/TaskTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/TaskTest.kt
@@ -4,6 +4,7 @@
package at.bitfire.ical4android
+import at.bitfire.ical4android.util.DateUtils
import net.fortuna.ical4j.model.*
import net.fortuna.ical4j.model.component.VAlarm
import net.fortuna.ical4j.model.parameter.RelType
diff --git a/src/androidTest/java/at/bitfire/ical4android/impl/TestJtxCollection.kt b/src/androidTest/java/at/bitfire/ical4android/impl/TestJtxCollection.kt
index 5a69060..2bef306 100644
--- a/src/androidTest/java/at/bitfire/ical4android/impl/TestJtxCollection.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/impl/TestJtxCollection.kt
@@ -9,7 +9,7 @@ import android.content.ContentProviderClient
import at.bitfire.ical4android.JtxCollection
import at.bitfire.ical4android.JtxCollectionFactory
import at.bitfire.ical4android.JtxICalObject
-import at.bitfire.ical4android.MiscUtils.CursorHelper.toValues
+import at.bitfire.ical4android.util.MiscUtils.CursorHelper.toValues
import at.techbee.jtx.JtxContract
import java.util.*
diff --git a/src/androidTest/java/at/bitfire/ical4android/AndroidTimeUtilsTest.kt b/src/androidTest/java/at/bitfire/ical4android/util/AndroidTimeUtilsTest.kt
index 9cb7653..18a37f9 100644
--- a/src/androidTest/java/at/bitfire/ical4android/AndroidTimeUtilsTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/util/AndroidTimeUtilsTest.kt
@@ -2,9 +2,8 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
-package at.bitfire.ical4android
+package at.bitfire.ical4android.util
-import at.bitfire.ical4android.util.AndroidTimeUtils
import net.fortuna.ical4j.data.CalendarBuilder
import net.fortuna.ical4j.model.*
import net.fortuna.ical4j.model.component.VTimeZone
diff --git a/src/androidTest/java/at/bitfire/ical4android/DateUtilsTest.kt b/src/androidTest/java/at/bitfire/ical4android/util/DateUtilsTest.kt
index 395b8da..fe1f468 100644
--- a/src/androidTest/java/at/bitfire/ical4android/DateUtilsTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/util/DateUtilsTest.kt
@@ -2,7 +2,7 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
-package at.bitfire.ical4android
+package at.bitfire.ical4android.util
import net.fortuna.ical4j.model.Date
import net.fortuna.ical4j.model.DateTime
diff --git a/src/androidTest/java/at/bitfire/ical4android/MiscUtilsAndroidTest.kt b/src/androidTest/java/at/bitfire/ical4android/util/MiscUtilsTest.kt
index d6f7e40..dee8dd9 100644
--- a/src/androidTest/java/at/bitfire/ical4android/MiscUtilsAndroidTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/util/MiscUtilsTest.kt
@@ -2,20 +2,20 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
-package at.bitfire.ical4android
+package at.bitfire.ical4android.util
import android.accounts.Account
import android.content.ContentValues
import android.database.MatrixCursor
import android.net.Uri
import androidx.test.filters.SmallTest
-import at.bitfire.ical4android.MiscUtils.CursorHelper.toValues
-import at.bitfire.ical4android.MiscUtils.UriHelper.asSyncAdapter
+import at.bitfire.ical4android.util.MiscUtils.CursorHelper.toValues
+import at.bitfire.ical4android.util.MiscUtils.UriHelper.asSyncAdapter
import org.junit.Assert
import org.junit.Assert.assertEquals
import org.junit.Test
-class MiscUtilsAndroidTest {
+class MiscUtilsTest {
private val tzVienna = DateUtils.ical4jTimeZone("Europe/Vienna")
diff --git a/src/androidTest/java/at/bitfire/ical4android/TimeApiExtensionsTest.kt b/src/androidTest/java/at/bitfire/ical4android/util/TimeApiExtensionsTest.kt
index 44a02a0..e5c6fc0 100644
--- a/src/androidTest/java/at/bitfire/ical4android/TimeApiExtensionsTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/util/TimeApiExtensionsTest.kt
@@ -2,7 +2,7 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
-package at.bitfire.ical4android
+package at.bitfire.ical4android.util
import at.bitfire.ical4android.util.TimeApiExtensions.requireTimeZone
import at.bitfire.ical4android.util.TimeApiExtensions.toDuration
@@ -28,7 +28,18 @@ class TimeApiExtensionsTest {
@Test
- fun testDateToLocalDate() {
+ fun testTimeZone_toZoneIdCompat_NotUtc() {
+ assertEquals(ZoneId.of("Europe/Berlin"), tzBerlin.toZoneId())
+ }
+
+ @Test
+ fun testTimeZone_toZoneIdCompat_Utc() {
+ assertEquals(ZoneOffset.UTC, TimeZones.getUtcTimeZone().toZoneIdCompat())
+ }
+
+
+ @Test
+ fun testDate_toLocalDate() {
val date = Date("20200620").toLocalDate()
assertEquals(2020, date.year)
assertEquals(6, date.monthValue)
@@ -38,19 +49,19 @@ class TimeApiExtensionsTest {
@Test
- fun testDateTimeRequireTimeZone() {
+ fun testDateTime_requireTimeZone() {
val time = DateTime("2020707T010203", tzBerlin)
assertEquals(tzBerlin, time.requireTimeZone())
}
@Test
- fun testDateTimeRequireTimeZone_Floating() {
+ fun testDateTime_requireTimeZone_Floating() {
val time = DateTime("2020707T010203")
assertEquals(TimeZone.getDefault(), time.requireTimeZone())
}
@Test
- fun testDateTimeRequireTimeZone_Utc() {
+ fun testDateTime_requireTimeZone_Utc() {
val time = DateTime("2020707T010203Z").apply { isUtc = true }
assertTrue(time.isUtc)
assertEquals(TimeZones.getUtcTimeZone(), time.requireTimeZone())
@@ -58,7 +69,7 @@ class TimeApiExtensionsTest {
@Test
- fun testDateTimeToLocalDate_TimezoneBoundary() {
+ fun testDateTime_toLocalDate_TimezoneBoundary() {
val date = DateTime("20200620T000000", tzBerlin).toLocalDate()
assertEquals(2020, date.year)
assertEquals(6, date.monthValue)
@@ -67,7 +78,7 @@ class TimeApiExtensionsTest {
}
@Test
- fun testDateTimeToLocalDate_TimezoneDuringDay() {
+ fun testDateTime_toLocalDate_TimezoneDuringDay() {
val date = DateTime("20200620T123000", tzBerlin).toLocalDate()
assertEquals(2020, date.year)
assertEquals(6, date.monthValue)
@@ -76,7 +87,7 @@ class TimeApiExtensionsTest {
}
@Test
- fun testDateTimeToLocalDate_UtcDuringDay() {
+ fun testDateTime_toLocalDate_UtcDuringDay() {
val date = DateTime("20200620T123000Z").apply { isUtc = true }.toLocalDate()
assertEquals(2020, date.year)
assertEquals(6, date.monthValue)
@@ -86,23 +97,23 @@ class TimeApiExtensionsTest {
@Test
- fun testDateTimeToLocalTime() {
+ fun testDateTime_toLocalTime() {
assertEquals(LocalTime.of(12, 30), DateTime("20200620T123000", tzBerlin).toLocalTime())
}
@Test
- fun testDateTimeToLocalTime_Floating() {
+ fun testDateTime_toLocalTime_Floating() {
assertEquals(LocalTime.of(12, 30), DateTime("20200620T123000").toLocalTime())
}
@Test
- fun testDateTimeToLocalTime_Utc() {
+ fun testDateTime_toLocalTime_Utc() {
assertEquals(LocalTime.of(12, 30), DateTime("20200620T123000Z").apply { isUtc = true }.toLocalTime())
}
@Test
- fun testDateTimeToZonedDateTime() {
+ fun testDateTime_toZonedDateTime() {
assertEquals(
ZonedDateTime.of(2020, 7, 7, 10, 30, 0, 0, tzBerlin.toZoneIdCompat()),
DateTime("20200707T103000", tzBerlin).toZonedDateTime()
@@ -110,7 +121,7 @@ class TimeApiExtensionsTest {
}
@Test
- fun testDateTimeToZonedDateTime_Floating() {
+ fun testDateTime_toZonedDateTime_Floating() {
assertEquals(
ZonedDateTime.of(2020, 7, 7, 10, 30, 0, 0, ZoneId.systemDefault()),
DateTime("20200707T103000").toZonedDateTime()
@@ -118,7 +129,7 @@ class TimeApiExtensionsTest {
}
@Test
- fun testDateTimeToZonedDateTime_UTC() {
+ fun testDateTime_toZonedDateTime_UTC() {
assertEquals(
ZonedDateTime.of(2020, 7, 7, 10, 30, 0, 0, ZoneOffset.UTC),
DateTime("20200707T103000Z").apply { isUtc = true }.toZonedDateTime()
@@ -127,31 +138,31 @@ class TimeApiExtensionsTest {
@Test
- fun testLocalDateToIcal4jDate() {
+ fun testLocalDate_toIcal4jDate() {
assertEquals(Date("19000118"), LocalDate.of(1900, 1, 18).toIcal4jDate())
assertEquals(Date("20200620"), LocalDate.of(2020, 6, 20).toIcal4jDate())
}
@Test
- fun testZonedDateTimeToIcal4jDateTime() {
+ fun testZonedDateTime_toIcal4jDateTime_NotUtc() {
val tzBerlin = DateUtils.ical4jTimeZone("Europe/Berlin")
assertEquals(
- DateTime("20200705T010203", tzBerlin),
- ZonedDateTime.of(2020, 7, 5, 1, 2, 3, 0, ZoneId.of("Europe/Berlin")).toIcal4jDateTime()
+ DateTime("20200705T010203", tzBerlin),
+ ZonedDateTime.of(2020, 7, 5, 1, 2, 3, 0, ZoneId.of("Europe/Berlin")).toIcal4jDateTime()
)
}
@Test
- fun testZonedDateTimeToIcal4jDateTime_Utc() {
+ fun testZonedDateTime_toIcal4jDateTime_Utc() {
assertEquals(
- DateTime("20200705T010203Z"),
- ZonedDateTime.of(2020, 7, 5, 1, 2, 3, 0, ZoneOffset.UTC).toIcal4jDateTime()
+ DateTime("20200705T010203Z"),
+ ZonedDateTime.of(2020, 7, 5, 1, 2, 3, 0, ZoneOffset.UTC).toIcal4jDateTime()
)
}
@Test
- fun testTemporalAmountToDuration() {
+ fun testTemporalAmount_toDuration() {
assertEquals(Duration.ofHours(1), Duration.ofHours(1).toDuration(Instant.EPOCH))
assertEquals(Duration.ofDays(1), Duration.ofDays(1).toDuration(Instant.EPOCH))
assertEquals(Duration.ofDays(1), Period.ofDays(1).toDuration(Instant.EPOCH))
@@ -161,7 +172,7 @@ class TimeApiExtensionsTest {
}
@Test
- fun testTemporalAmountToRfc5545Duration_Duration() {
+ fun testTemporalAmount_toRfc5545Duration_Duration() {
assertEquals("P0S", Duration.ofDays(0).toRfc5545Duration(Instant.EPOCH))
assertEquals("P2W", Duration.ofDays(14).toRfc5545Duration(Instant.EPOCH))
assertEquals("P15D", Duration.ofDays(15).toRfc5545Duration(Instant.EPOCH))
diff --git a/src/androidTest/java/at/bitfire/ical4android/validation/EventValidatorTest.kt b/src/androidTest/java/at/bitfire/ical4android/validation/EventValidatorTest.kt
index 2af3fe8..fa3d959 100644
--- a/src/androidTest/java/at/bitfire/ical4android/validation/EventValidatorTest.kt
+++ b/src/androidTest/java/at/bitfire/ical4android/validation/EventValidatorTest.kt
@@ -6,14 +6,12 @@ package at.bitfire.ical4android.validation
import at.bitfire.ical4android.Event
import at.bitfire.ical4android.InvalidCalendarException
-import net.fortuna.ical4j.model.Date
-import net.fortuna.ical4j.model.DateTime
-import net.fortuna.ical4j.model.Recur
-import net.fortuna.ical4j.model.TimeZoneRegistryFactory
+import net.fortuna.ical4j.model.*
import net.fortuna.ical4j.model.property.DtEnd
import net.fortuna.ical4j.model.property.DtStart
import net.fortuna.ical4j.model.property.RRule
import org.junit.Assert.*
+import org.junit.Assume
import org.junit.Test
import java.io.StringReader
@@ -79,10 +77,10 @@ class EventValidatorTest {
rRules.add(RRule("FREQ=MONTHLY;UNTIL=20251214T001100Z")) // DATETIME (UTC)
}
assertEquals(DateTime("20211115T001100Z"), event.dtStart!!.date)
- assertEquals(DateTime("20251214T001100Z"), event.rRules.first.recur.until)
+ assertEquals("FREQ=MONTHLY;UNTIL=20251214T001100Z", event.rRules.joinToString())
EventValidator.sameTypeForDtStartAndRruleUntil(event.dtStart!!, event.rRules)
assertEquals(DateTime("20211115T001100Z"), event.dtStart!!.date)
- assertEquals(DateTime("20251214T001100Z"), event.rRules.first.recur.until)
+ assertEquals("FREQ=MONTHLY;UNTIL=20251214T001100Z", event.rRules.joinToString())
val event1 = Event.eventsFromReader(StringReader(
"BEGIN:VCALENDAR\n" +
@@ -92,7 +90,7 @@ class EventValidatorTest {
"RRULE:FREQ=MONTHLY;UNTIL=20231214;BYMONTHDAY=15\n" + // DATE
"END:VEVENT\n" +
"END:VCALENDAR")).first()
- assertEquals(Date("20231214"), event1.rRules.first.recur.until)
+ assertEquals("FREQ=MONTHLY;UNTIL=20231214;BYMONTHDAY=15", event1.rRules.joinToString())
val event2 = Event.eventsFromReader(StringReader(
"BEGIN:VCALENDAR\n" +
@@ -102,7 +100,7 @@ class EventValidatorTest {
"RRULE:FREQ=YEARLY;UNTIL=20230216;BYMONTHDAY=15\n" + // DATE
"END:VEVENT\n" +
"END:VCALENDAR")).first()
- assertEquals(Date("20230216"), event2.rRules.first.recur.until)
+ assertEquals("FREQ=YEARLY;UNTIL=20230216;BYMONTHDAY=15", event2.rRules.joinToString())
}
@Test
@@ -119,7 +117,7 @@ class EventValidatorTest {
event.rRules.first.recur.until
)
EventValidator.sameTypeForDtStartAndRruleUntil(event.dtStart!!, event.rRules)
- assertEquals(Date("20211214"), event.rRules.first.recur.until)
+ assertEquals("FREQ=MONTHLY;UNTIL=20211214", event.rRules.joinToString())
val event1 = Event.eventsFromReader(
StringReader(
@@ -133,7 +131,7 @@ class EventValidatorTest {
)
).first()
assertEquals(1639440000000, event1.rRules.first.recur.until.time)
- assertEquals(Date("20211214"), event1.rRules.first.recur.until)
+ assertEquals("FREQ=MONTHLY;UNTIL=20211214;BYMONTHDAY=15", event1.rRules.joinToString())
}
@Test
@@ -150,22 +148,22 @@ class EventValidatorTest {
// As it does not happen often, for the sake of simplicity we just accept either
EventValidator.sameTypeForDtStartAndRruleUntil(event2.dtStart!!, event2.rRules)
assertTrue(
- Date("20230218") == event2.rRules.first.recur.until ||
- Date("20230217") == event2.rRules.first.recur.until
+ "FREQ=YEARLY;UNTIL=20230218;BYMONTHDAY=15" == event2.rRules.joinToString() ||
+ "FREQ=YEARLY;UNTIL=20230217;BYMONTHDAY=15" == event2.rRules.joinToString()
)
}
@Test
- fun testSameTypeForDtStartAndRruleUntil_DtStartIsDateTimeAndRruleUntilIsDate() {
+ fun testSameTypeForDtStartAndRruleUntil_DtStartIsDateTimeWithTzAndRruleUntilIsDate() {
// should add (possibly missing) time in UNTIL if DTSTART value is of type DATETIME (not just DATE)
val event = Event().apply {
dtStart = DtStart(DateTime("20110605T001100Z")) // DATETIME (UTC)
rRules.add(RRule("FREQ=MONTHLY;UNTIL=20211214")) // DATE
}
- assertEquals(Date("20211214"), event.rRules.first.recur.until)
+ assertEquals("FREQ=MONTHLY;UNTIL=20211214", event.rRules.joinToString())
EventValidator.sameTypeForDtStartAndRruleUntil(event.dtStart!!, event.rRules)
- assertEquals(DateTime("20211214T001100Z"), event.rRules.first.recur.until)
+ assertEquals("FREQ=MONTHLY;UNTIL=20211214T001100Z", event.rRules.joinToString())
val event1 = Event.eventsFromReader(StringReader(
"BEGIN:VCALENDAR\n" +
@@ -175,17 +173,34 @@ class EventValidatorTest {
"RRULE:FREQ=MONTHLY;UNTIL=20211214;BYMONTHDAY=15\n" + // DATE
"END:VEVENT\n" +
"END:VCALENDAR")).first()
- assertEquals(DateTime("20211214T053000", tzReg.getTimeZone("America/New_York")), event1.rRules.first.recur.until)
+ assertEquals("FREQ=MONTHLY;UNTIL=20211214T103000Z;BYMONTHDAY=15", event1.rRules.joinToString())
+ }
- val event2 = Event.eventsFromReader(StringReader(
- "BEGIN:VCALENDAR\n" +
- "BEGIN:VEVENT\n" +
- "UID:381fb26b-2da5-4dd2-94d7-2e0874128aa7\n" +
- "DTSTART;VALUE=DATETIME:20080214T001100\n" + // DATETIME (no timezone)
- "RRULE:FREQ=YEARLY;UNTIL=20110214;BYMONTHDAY=15\n" + // DATE
- "END:VEVENT\n" +
- "END:VCALENDAR")).first()
- assertEquals(DateTime("20110214T001100"), event2.rRules.first.recur.until)
+ @Test
+ fun testSameTypeForDtStartAndRruleUntil_DtStartIsDateTimeWithoutTzAndRruleUntilIsDate() {
+ // should add (possibly missing) time in UNTIL if DTSTART value is of type DATETIME (not just DATE)
+
+ val event = Event().apply {
+ dtStart = DtStart(DateTime("20110605T001100Z")) // DATETIME (UTC)
+ rRules.add(RRule("FREQ=MONTHLY;UNTIL=20211214")) // DATE
+ }
+ assertEquals("FREQ=MONTHLY;UNTIL=20211214", event.rRules.joinToString())
+ EventValidator.sameTypeForDtStartAndRruleUntil(event.dtStart!!, event.rRules)
+ assertEquals("FREQ=MONTHLY;UNTIL=20211214T001100Z", event.rRules.joinToString())
+
+ Assume.assumeTrue(TimeZone.getDefault().id == "Europe/Vienna")
+ val event2 = Event.eventsFromReader(
+ StringReader(
+ "BEGIN:VCALENDAR\n" +
+ "BEGIN:VEVENT\n" +
+ "UID:381fb26b-2da5-4dd2-94d7-2e0874128aa7\n" +
+ "DTSTART;VALUE=DATETIME:20080214T001100\n" + // DATETIME (no timezone)
+ "RRULE:FREQ=YEARLY;UNTIL=20110214;BYMONTHDAY=15\n" + // DATE
+ "END:VEVENT\n" +
+ "END:VCALENDAR"
+ )
+ ).first()
+ assertEquals("FREQ=YEARLY;UNTIL=20110213T231100Z;BYMONTHDAY=15", event2.rRules.joinToString())
}
@@ -311,4 +326,10 @@ class EventValidatorTest {
), rrules.toTypedArray())
}
+
+ // helpers
+
+ private fun Iterable<RRule>.joinToString(): String =
+ this.map { rRule -> rRule.value }.joinToString("\n")
+
} \ No newline at end of file
diff --git a/src/main/java/at/bitfire/ical4android/AndroidCalendar.kt b/src/main/java/at/bitfire/ical4android/AndroidCalendar.kt
index 398da20..aa92e57 100644
--- a/src/main/java/at/bitfire/ical4android/AndroidCalendar.kt
+++ b/src/main/java/at/bitfire/ical4android/AndroidCalendar.kt
@@ -10,8 +10,8 @@ import android.content.ContentUris
import android.content.ContentValues
import android.net.Uri
import android.provider.CalendarContract.*
-import at.bitfire.ical4android.MiscUtils.CursorHelper.toValues
-import at.bitfire.ical4android.MiscUtils.UriHelper.asSyncAdapter
+import at.bitfire.ical4android.util.MiscUtils.CursorHelper.toValues
+import at.bitfire.ical4android.util.MiscUtils.UriHelper.asSyncAdapter
import java.io.FileNotFoundException
import java.util.*
import java.util.logging.Level
diff --git a/src/main/java/at/bitfire/ical4android/AndroidEvent.kt b/src/main/java/at/bitfire/ical4android/AndroidEvent.kt
index 4230ee0..8648dd5 100644
--- a/src/main/java/at/bitfire/ical4android/AndroidEvent.kt
+++ b/src/main/java/at/bitfire/ical4android/AndroidEvent.kt
@@ -14,9 +14,11 @@ import android.provider.CalendarContract.*
import android.util.Patterns
import androidx.annotation.CallSuper
import at.bitfire.ical4android.BatchOperation.CpoBuilder
-import at.bitfire.ical4android.MiscUtils.CursorHelper.toValues
-import at.bitfire.ical4android.MiscUtils.UriHelper.asSyncAdapter
import at.bitfire.ical4android.util.AndroidTimeUtils
+import at.bitfire.ical4android.util.DateUtils
+import at.bitfire.ical4android.util.MiscUtils
+import at.bitfire.ical4android.util.MiscUtils.CursorHelper.toValues
+import at.bitfire.ical4android.util.MiscUtils.UriHelper.asSyncAdapter
import at.bitfire.ical4android.util.TimeApiExtensions
import at.bitfire.ical4android.util.TimeApiExtensions.requireZoneId
import at.bitfire.ical4android.util.TimeApiExtensions.toIcal4jDate
@@ -25,7 +27,6 @@ import at.bitfire.ical4android.util.TimeApiExtensions.toLocalDate
import at.bitfire.ical4android.util.TimeApiExtensions.toLocalTime
import at.bitfire.ical4android.util.TimeApiExtensions.toRfc5545Duration
import at.bitfire.ical4android.util.TimeApiExtensions.toZonedDateTime
-import at.bitfire.ical4android.validation.EventValidator
import net.fortuna.ical4j.model.*
import net.fortuna.ical4j.model.Date
import net.fortuna.ical4j.model.component.VAlarm
@@ -780,10 +781,11 @@ abstract class AndroidEvent(
builder .withValue(Events.DURATION, duration?.toRfc5545Duration(dtStart.date.toInstant()))
.withValue(Events.DTEND, null)
- // add RRULe
- if (event.rRules.isNotEmpty())
- builder.withValue(Events.RRULE, event.rRules.joinToString(AndroidTimeUtils.RECURRENCE_RULE_SEPARATOR) { it.value })
- else
+ // add RRULEs
+ if (event.rRules.isNotEmpty()) {
+ builder.withValue(Events.RRULE, event.rRules
+ .joinToString(AndroidTimeUtils.RECURRENCE_RULE_SEPARATOR) { it.value })
+ } else
builder.withValue(Events.RRULE, null)
if (event.rDates.isNotEmpty()) {
diff --git a/src/main/java/at/bitfire/ical4android/AndroidTask.kt b/src/main/java/at/bitfire/ical4android/AndroidTask.kt
index 84af609..3e56dc1 100644
--- a/src/main/java/at/bitfire/ical4android/AndroidTask.kt
+++ b/src/main/java/at/bitfire/ical4android/AndroidTask.kt
@@ -10,8 +10,10 @@ import android.net.Uri
import android.os.RemoteException
import androidx.annotation.CallSuper
import at.bitfire.ical4android.BatchOperation.CpoBuilder
-import at.bitfire.ical4android.MiscUtils.CursorHelper.toValues
import at.bitfire.ical4android.util.AndroidTimeUtils
+import at.bitfire.ical4android.util.DateUtils
+import at.bitfire.ical4android.util.MiscUtils
+import at.bitfire.ical4android.util.MiscUtils.CursorHelper.toValues
import net.fortuna.ical4j.model.*
import net.fortuna.ical4j.model.Date
import net.fortuna.ical4j.model.TimeZone
diff --git a/src/main/java/at/bitfire/ical4android/AndroidTaskList.kt b/src/main/java/at/bitfire/ical4android/AndroidTaskList.kt
index 8439d80..01215fe 100644
--- a/src/main/java/at/bitfire/ical4android/AndroidTaskList.kt
+++ b/src/main/java/at/bitfire/ical4android/AndroidTaskList.kt
@@ -8,8 +8,8 @@ import android.accounts.Account
import android.content.ContentUris
import android.content.ContentValues
import android.net.Uri
-import at.bitfire.ical4android.MiscUtils.CursorHelper.toValues
-import at.bitfire.ical4android.MiscUtils.UriHelper.asSyncAdapter
+import at.bitfire.ical4android.util.MiscUtils.CursorHelper.toValues
+import at.bitfire.ical4android.util.MiscUtils.UriHelper.asSyncAdapter
import org.dmfs.tasks.contract.TaskContract
import org.dmfs.tasks.contract.TaskContract.Property.Relation
import org.dmfs.tasks.contract.TaskContract.TaskLists
diff --git a/src/main/java/at/bitfire/ical4android/Event.kt b/src/main/java/at/bitfire/ical4android/Event.kt
index 3f2e567..7c6449b 100644
--- a/src/main/java/at/bitfire/ical4android/Event.kt
+++ b/src/main/java/at/bitfire/ical4android/Event.kt
@@ -4,8 +4,8 @@
package at.bitfire.ical4android
-import at.bitfire.ical4android.DateUtils.isDateTime
import at.bitfire.ical4android.ICalendar.Companion.CALENDAR_NAME
+import at.bitfire.ical4android.util.DateUtils.isDateTime
import at.bitfire.ical4android.validation.EventValidator
import net.fortuna.ical4j.data.CalendarOutputter
import net.fortuna.ical4j.data.ParserException
diff --git a/src/main/java/at/bitfire/ical4android/ICalendar.kt b/src/main/java/at/bitfire/ical4android/ICalendar.kt
index 678b195..c519278 100644
--- a/src/main/java/at/bitfire/ical4android/ICalendar.kt
+++ b/src/main/java/at/bitfire/ical4android/ICalendar.kt
@@ -4,6 +4,7 @@
package at.bitfire.ical4android
+import at.bitfire.ical4android.util.MiscUtils
import at.bitfire.ical4android.validation.ICalPreprocessor
import net.fortuna.ical4j.data.CalendarBuilder
import net.fortuna.ical4j.data.ParserException
diff --git a/src/main/java/at/bitfire/ical4android/JtxCollection.kt b/src/main/java/at/bitfire/ical4android/JtxCollection.kt
index 1527ef5..dc920be 100644
--- a/src/main/java/at/bitfire/ical4android/JtxCollection.kt
+++ b/src/main/java/at/bitfire/ical4android/JtxCollection.kt
@@ -10,7 +10,7 @@ import android.content.ContentUris
import android.content.ContentValues
import android.content.Context
import android.net.Uri
-import at.bitfire.ical4android.MiscUtils.CursorHelper.toValues
+import at.bitfire.ical4android.util.MiscUtils.CursorHelper.toValues
import at.techbee.jtx.JtxContract
import at.techbee.jtx.JtxContract.asSyncAdapter
import net.fortuna.ical4j.model.Calendar
diff --git a/src/main/java/at/bitfire/ical4android/JtxICalObject.kt b/src/main/java/at/bitfire/ical4android/JtxICalObject.kt
index 91d53ed..fd17ed9 100644
--- a/src/main/java/at/bitfire/ical4android/JtxICalObject.kt
+++ b/src/main/java/at/bitfire/ical4android/JtxICalObject.kt
@@ -10,7 +10,7 @@ import android.net.ParseException
import android.net.Uri
import android.os.ParcelFileDescriptor
import android.util.Base64
-import at.bitfire.ical4android.MiscUtils.CursorHelper.toValues
+import at.bitfire.ical4android.util.MiscUtils.CursorHelper.toValues
import at.techbee.jtx.JtxContract
import at.techbee.jtx.JtxContract.JtxICalObject.TZ_ALLDAY
import at.techbee.jtx.JtxContract.asSyncAdapter
diff --git a/src/main/java/at/bitfire/ical4android/Task.kt b/src/main/java/at/bitfire/ical4android/Task.kt
index 0e70ca0..b19e1c6 100644
--- a/src/main/java/at/bitfire/ical4android/Task.kt
+++ b/src/main/java/at/bitfire/ical4android/Task.kt
@@ -5,6 +5,7 @@
package at.bitfire.ical4android
import androidx.annotation.IntRange
+import at.bitfire.ical4android.util.DateUtils
import net.fortuna.ical4j.data.CalendarOutputter
import net.fortuna.ical4j.data.ParserException
import net.fortuna.ical4j.model.*
diff --git a/src/main/java/at/bitfire/ical4android/TaskProvider.kt b/src/main/java/at/bitfire/ical4android/TaskProvider.kt
index 6754388..a9a14e3 100644
--- a/src/main/java/at/bitfire/ical4android/TaskProvider.kt
+++ b/src/main/java/at/bitfire/ical4android/TaskProvider.kt
@@ -9,7 +9,7 @@ import android.content.ContentProviderClient
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.content.pm.PackageInfoCompat
-import at.bitfire.ical4android.MiscUtils.ContentProviderClientHelper.closeCompat
+import at.bitfire.ical4android.util.MiscUtils.ContentProviderClientHelper.closeCompat
import org.dmfs.tasks.contract.TaskContract
import java.io.Closeable
import java.util.logging.Level
diff --git a/src/main/java/at/bitfire/ical4android/util/AndroidTimeUtils.kt b/src/main/java/at/bitfire/ical4android/util/AndroidTimeUtils.kt
index 9d22cd8..337ab41 100644
--- a/src/main/java/at/bitfire/ical4android/util/AndroidTimeUtils.kt
+++ b/src/main/java/at/bitfire/ical4android/util/AndroidTimeUtils.kt
@@ -7,7 +7,6 @@
package at.bitfire.ical4android.util
import android.text.format.Time
-import at.bitfire.ical4android.DateUtils
import at.bitfire.ical4android.Ical4Android
import net.fortuna.ical4j.model.*
import net.fortuna.ical4j.model.Date
diff --git a/src/main/java/at/bitfire/ical4android/DateUtils.kt b/src/main/java/at/bitfire/ical4android/util/DateUtils.kt
index c9ceffa..6c0060e 100644
--- a/src/main/java/at/bitfire/ical4android/DateUtils.kt
+++ b/src/main/java/at/bitfire/ical4android/util/DateUtils.kt
@@ -2,8 +2,10 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
-package at.bitfire.ical4android
+package at.bitfire.ical4android.util
+import at.bitfire.ical4android.Ical4Android
+import at.bitfire.ical4android.UsesThreadContextClassLoader
import net.fortuna.ical4j.data.CalendarBuilder
import net.fortuna.ical4j.model.Date
import net.fortuna.ical4j.model.DateTime
diff --git a/src/main/java/at/bitfire/ical4android/MiscUtils.kt b/src/main/java/at/bitfire/ical4android/util/MiscUtils.kt
index 0c76624..76b3e02 100644
--- a/src/main/java/at/bitfire/ical4android/MiscUtils.kt
+++ b/src/main/java/at/bitfire/ical4android/util/MiscUtils.kt
@@ -2,7 +2,7 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
-package at.bitfire.ical4android
+package at.bitfire.ical4android.util
import android.accounts.Account
import android.content.ContentProviderClient
diff --git a/src/main/java/at/bitfire/ical4android/util/TimeApiExtensions.kt b/src/main/java/at/bitfire/ical4android/util/TimeApiExtensions.kt
index f9b1ac1..9ff5529 100644
--- a/src/main/java/at/bitfire/ical4android/util/TimeApiExtensions.kt
+++ b/src/main/java/at/bitfire/ical4android/util/TimeApiExtensions.kt
@@ -4,7 +4,6 @@
package at.bitfire.ical4android.util
-import at.bitfire.ical4android.DateUtils
import net.fortuna.ical4j.model.Date
import net.fortuna.ical4j.model.DateTime
import net.fortuna.ical4j.util.TimeZones
@@ -31,8 +30,15 @@ object TimeApiExtensions {
/**
* [TimeZone.toZoneId] can't be used with the current desugaring library yet!
+ *
+ * @return [ZoneId] of the time zone; [ZoneOffset.UTC] if the time zone equals to [TimeZones.getUtcTimeZone]
*/
- fun TimeZone.toZoneIdCompat(): ZoneId = ZoneId.of(id)
+ fun TimeZone.toZoneIdCompat(): ZoneId {
+ return if (this == TimeZones.getUtcTimeZone())
+ ZoneOffset.UTC
+ else
+ ZoneId.of(id)
+ }
/***** Dates *****/
@@ -69,6 +75,15 @@ object TimeApiExtensions {
return Date(cal)
}
+ /**
+ * Converts this zoned date-time (date/time with specific time zone) to an
+ * ical4j [DateTime] object.
+ *
+ * Sets UTC flag ([DateTime.isUtc], means `...ThhmmddZ` format) when this zone-date time object has a
+ * time zone of [ZoneOffset.UTC].
+ *
+ * @return ical4j [DateTime] of the given zoned date-time
+ */
fun ZonedDateTime.toIcal4jDateTime(): DateTime {
val date = DateTime(toEpochSecond() * MILLIS_PER_SECOND)
if (zone == ZoneOffset.UTC)
diff --git a/src/main/java/at/bitfire/ical4android/validation/EventValidator.kt b/src/main/java/at/bitfire/ical4android/validation/EventValidator.kt
index d8ee48c..71e6147 100644
--- a/src/main/java/at/bitfire/ical4android/validation/EventValidator.kt
+++ b/src/main/java/at/bitfire/ical4android/validation/EventValidator.kt
@@ -4,15 +4,15 @@
package at.bitfire.ical4android.validation
-import at.bitfire.ical4android.DateUtils
import at.bitfire.ical4android.Event
import at.bitfire.ical4android.Ical4Android
import at.bitfire.ical4android.InvalidCalendarException
+import at.bitfire.ical4android.util.DateUtils
import at.bitfire.ical4android.util.TimeApiExtensions.toIcal4jDate
-import at.bitfire.ical4android.util.TimeApiExtensions.toIcal4jDateTime
import at.bitfire.ical4android.util.TimeApiExtensions.toLocalDate
import at.bitfire.ical4android.util.TimeApiExtensions.toZoneIdCompat
import net.fortuna.ical4j.model.DateTime
+import net.fortuna.ical4j.model.Recur
import net.fortuna.ical4j.model.property.DtStart
import net.fortuna.ical4j.model.property.RRule
import net.fortuna.ical4j.util.TimeZones
@@ -52,16 +52,36 @@ class EventValidator(val e: Event) {
*/
internal fun sameTypeForDtStartAndRruleUntil(dtStart: DtStart, rRules: MutableList<RRule>) {
if (DateUtils.isDate(dtStart)) {
- for (rRule in rRules) {
+ // DTSTART is a DATE
+ val newRRules = mutableListOf<RRule>()
+ val rRuleIterator = rRules.iterator()
+ while (rRuleIterator.hasNext()) {
+ val rRule = rRuleIterator.next()
rRule.recur.until?.let { until ->
if (until is DateTime) {
Ical4Android.log.warning("DTSTART has DATE, but UNTIL has DATETIME; making UNTIL have DATE only")
- rRule.recur.until = until.toLocalDate().toIcal4jDate()
+
+ val newUntil = until.toLocalDate().toIcal4jDate()
+
+ // remove current RRULE and remember new one to be added
+ val newRRule = RRule(Recur.Builder(rRule.recur)
+ .until(newUntil)
+ .build())
+ Ical4Android.log.info("New $newRRule (was ${rRule.toString().trim()})")
+ newRRules += newRRule
+ rRuleIterator.remove()
}
}
}
+ // add repaired RRULEs
+ rRules += newRRules
+
} else if (DateUtils.isDateTime(dtStart)) {
- for (rRule in rRules) {
+ // DTSTART is a DATE-TIME
+ val newRRules = mutableListOf<RRule>()
+ val rRuleIterator = rRules.iterator()
+ while (rRuleIterator.hasNext()) {
+ val rRule = rRuleIterator.next()
rRule.recur.until?.let { until ->
if (until !is DateTime) {
Ical4Android.log.warning("DTSTART has DATETIME, but UNTIL has DATE; copying time from DTSTART to UNTIL")
@@ -81,15 +101,30 @@ class EventValidator(val e: Event) {
dtStartCal.get(Calendar.SECOND)
)
- rRule.recur.until =
- ZonedDateTime.of(
- until.toLocalDate(), // date from until
- dtStartTime, // time from dtStart
- dtStartTimeZone.toZoneIdCompat()
- ).toIcal4jDateTime()
+ val newUntil = ZonedDateTime.of(
+ until.toLocalDate(), // date from until
+ dtStartTime, // time from dtStart
+ dtStartTimeZone.toZoneIdCompat()
+ )
+
+ // Android requires UNTIL in UTC as defined in RFC 2445.
+ // https://android.googlesource.com/platform/frameworks/opt/calendar/+/refs/tags/android-12.1.0_r27/src/com/android/calendarcommon2/RecurrenceProcessor.java#93
+ val newUntilUTC = DateTime(true).apply {
+ time = newUntil.toInstant().toEpochMilli()
+ }
+
+ // remove current RRULE and remember new one to be added
+ val newRRule = RRule(Recur.Builder(rRule.recur)
+ .until(newUntilUTC)
+ .build())
+ Ical4Android.log.info("New $newRRule (was ${rRule.toString().trim()})")
+ newRRules += newRRule
+ rRuleIterator.remove()
}
}
}
+ // add repaired RRULEs
+ rRules += newRRules
} else
throw InvalidCalendarException("Event with invalid DTSTART value")
}
diff --git a/src/test/java/at/bitfire/ical4android/MiscUtilsTest.kt b/src/test/java/at/bitfire/ical4android/MiscUtilsTest.kt
index e32ba0a..c9cf19d 100644
--- a/src/test/java/at/bitfire/ical4android/MiscUtilsTest.kt
+++ b/src/test/java/at/bitfire/ical4android/MiscUtilsTest.kt
@@ -4,6 +4,7 @@
package at.bitfire.ical4android
+import at.bitfire.ical4android.util.MiscUtils
import org.junit.Assert.assertTrue
import org.junit.Test