@@ -24,37 +24,53 @@ import java.time.temporal.Temporal
2424
2525object EventHandler : DataRowHandler() {
2626
27- // source: https://android.googlesource.com/platform/packages/apps/Contacts/+/c326c157541978c180be4e3432327eceb1e66637/src/com/android/contacts/util/CommonDateUtils.java#25
28- private val acceptableFormats: List <Pair <DateTimeFormatter , (String , DateTimeFormatter ) - > Temporal >> = listOf (
29- // Formats provided by Android's CommonDateUtils
30- DateTimeFormatter .ofPattern(" yyyy-MM-dd'T'HH:mm:ss.SSSXXX" ) to OffsetDateTime ::parse,
31- DateTimeFormatter .ofPattern(" yyyy-MM-dd" ) to LocalDate ::parse,
32- // Additional common formats
33- DateTimeFormatter .ISO_OFFSET_DATE_TIME to OffsetDateTime ::parse, // "yyyy-MM-dd'T'HH:mm:ssXXX"
27+ // CommonDateUtils: https://android.googlesource.com/platform/packages/apps/Contacts/+/c326c157541978c180be4e3432327eceb1e66637/src/com/android/contacts/util/CommonDateUtils.java#25
28+
29+ /* *
30+ * Date formats for full date with time. Converts to [OffsetDateTime].
31+ */
32+ private val fullDateTimeFormats = listOf (
33+ // Provided by Android's CommonDateUtils
34+ DateTimeFormatter .ofPattern(" yyyy-MM-dd'T'HH:mm:ss.SSSXXX" ),
35+ // "yyyy-MM-dd'T'HH:mm:ssXXX"
36+ DateTimeFormatter .ISO_OFFSET_DATE_TIME ,
3437 )
3538
39+ /* *
40+ * Date format for full date without time. Converts to [LocalDate].
41+ */
42+ private val fullDateFormat = DateTimeFormatter .ofPattern(" yyyy-MM-dd" )
43+
44+
3645 override fun forMimeType () = Event .CONTENT_ITEM_TYPE
3746
3847 /* *
3948 * Tries to parse a date string into a [Temporal] object using multiple acceptable formats.
4049 * Returns the parsed [Temporal] if successful, or `null` if none of the formats match.
4150 * @param dateString The date string to parse.
4251 * @return If format is:
43- * - `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'` or `yyyy-MM-dd'T'HH:mm:ssXXX` -> [OffsetDateTime]
44- * - `yyyy-MM-dd` -> [LocalDate]
52+ * - `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'` or `yyyy-MM-dd'T'HH:mm:ssXXX` ([fullDateTimeFormats]) -> [OffsetDateTime]
53+ * - `yyyy-MM-dd` ([fullDateFormat]) -> [LocalDate]
4554 * - else -> `null`
4655 */
4756 @VisibleForTesting
48- internal fun parseStartDate (dateString : String ): Temporal ? {
49- for (( formatter, parse) in acceptableFormats ) {
57+ internal fun parseFullDate (dateString : String ): Temporal ? {
58+ for (formatter in fullDateTimeFormats ) {
5059 try {
51- return parse(dateString, formatter)
60+ return OffsetDateTime . parse(dateString, formatter)
5261 } catch (_: DateTimeParseException ) {
5362 // ignore: given date is not valid
5463 continue
5564 }
5665 }
5766
67+ // try parsing as full date only (no time)
68+ try {
69+ return LocalDate .parse(dateString, fullDateFormat)
70+ } catch (_: DateTimeParseException ) {
71+ // ignore: given date is not valid
72+ }
73+
5874 // could not parse date
5975 return null
6076 }
@@ -72,6 +88,8 @@ object EventHandler : DataRowHandler() {
7288 internal fun parsePartialDate (dateString : String ): PartialDate ? {
7389 var dateString = dateString // to allow modification
7490 return try {
91+ // convert Android partial date/date-time to vCard partial date/date-time so that it can be parsed by ez-vcard
92+
7593 if (dateString.endsWith(' Z' )) {
7694 // 'Z' is not supported for suffix in PartialDate, replace with actual offset
7795 dateString = dateString.removeSuffix(" Z" ) + " +00:00"
@@ -95,7 +113,7 @@ object EventHandler : DataRowHandler() {
95113 super .handle(values, contact)
96114
97115 val dateStr = values.getAsString(Event .START_DATE ) ? : return
98- val full: Temporal ? = parseStartDate (dateStr)
116+ val full: Temporal ? = parseFullDate (dateStr)
99117 val partial: PartialDate ? = if (full == null ) {
100118 parsePartialDate(dateStr)
101119 } else {
0 commit comments