Fix some CalDAV time zone conversions

pull/1322/head
Alex Baker 5 years ago
parent d8658b1db0
commit d8e8c1b1a6

@ -237,7 +237,7 @@ class Task : Parcelable {
repeatUntil = 0 repeatUntil = 0
recurrence = null recurrence = null
} else { } else {
repeatUntil = rrule.recur.until?.let { DateTime.from(it).millis } ?: 0 repeatUntil = rrule.recur.until?.let { DateTime(it).millis } ?: 0
recurrence = "RRULE:${rrule.value.sanitizeRRule()}" + if (repeatAfterCompletion()) ";FROM=COMPLETION" else "" recurrence = "RRULE:${rrule.value.sanitizeRRule()}" + if (repeatAfterCompletion()) ";FROM=COMPLETION" else ""
} }
} }

@ -1,18 +1,15 @@
package org.tasks.caldav; package org.tasks.caldav;
import static com.todoroo.andlib.utility.DateUtilities.now; import static com.todoroo.andlib.utility.DateUtilities.now;
import static com.todoroo.astrid.data.Task.URGENCY_SPECIFIC_DAY; import static org.tasks.caldav.iCalendar.getLocal;
import static com.todoroo.astrid.data.Task.URGENCY_SPECIFIC_DAY_TIME;
import static org.tasks.date.DateTimeUtils.newDateTime; import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.time.DateTime.UTC;
import static org.tasks.time.DateTimeUtils.startOfDay; import static org.tasks.time.DateTimeUtils.startOfDay;
import at.bitfire.ical4android.DateUtils; import at.bitfire.ical4android.DateUtils;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.Task.Priority; import com.todoroo.astrid.data.Task.Priority;
import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import net.fortuna.ical4j.model.Date; import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.DateTime; import net.fortuna.ical4j.model.DateTime;
@ -26,12 +23,10 @@ import timber.log.Timber;
public class CaldavConverter { public class CaldavConverter {
static final DateFormat DUE_DATE_FORMAT = new SimpleDateFormat("yyyyMMdd", Locale.US);
public static void apply(Task local, at.bitfire.ical4android.Task remote) { public static void apply(Task local, at.bitfire.ical4android.Task remote) {
Completed completedAt = remote.getCompletedAt(); Completed completedAt = remote.getCompletedAt();
if (completedAt != null) { if (completedAt != null) {
local.setCompletionDate(remote.getCompletedAt().getDate().getTime()); local.setCompletionDate(getLocal(completedAt));
} else if (remote.getStatus() == Status.VTODO_COMPLETED) { } else if (remote.getStatus() == Status.VTODO_COMPLETED) {
if (!local.isCompleted()) { if (!local.isCompleted()) {
local.setCompletionDate(now()); local.setCompletionDate(now());
@ -39,32 +34,15 @@ public class CaldavConverter {
} else { } else {
local.setCompletionDate(0L); local.setCompletionDate(0L);
} }
Long createdAt = remote.getCreatedAt(); Long createdAt = remote.getCreatedAt();
if (createdAt != null) { if (createdAt != null) {
local.setCreationDate(newDateTime(createdAt).toLocal().getMillis()); local.setCreationDate(newDateTime(createdAt, UTC).toLocal().getMillis());
} }
local.setTitle(remote.getSummary()); local.setTitle(remote.getSummary());
local.setNotes(remote.getDescription()); local.setNotes(remote.getDescription());
local.setPriority(fromRemote(remote.getPriority())); local.setPriority(fromRemote(remote.getPriority()));
local.setRecurrence(remote.getRRule()); local.setRecurrence(remote.getRRule());
Due due = remote.getDue(); iCalendar.Companion.apply(remote.getDue(), local);
if (due == null) {
local.setDueDate(0L);
} else {
Date dueDate = due.getDate();
if (dueDate instanceof DateTime) {
local.setDueDate(Task.createDueDate(URGENCY_SPECIFIC_DAY_TIME, dueDate.getTime()));
} else {
try {
local.setDueDate(
Task.createDueDate(
URGENCY_SPECIFIC_DAY, DUE_DATE_FORMAT.parse(due.getValue()).getTime()));
} catch (ParseException e) {
Timber.e(e);
}
}
}
iCalendar.Companion.apply(remote.getDtStart(), local); iCalendar.Companion.apply(remote.getDtStart(), local);
} }

@ -5,18 +5,16 @@ import at.bitfire.ical4android.Task.Companion.tasksFromReader
import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task.Companion.HIDE_UNTIL_SPECIFIC_DAY import com.todoroo.astrid.data.Task.Companion.HIDE_UNTIL_SPECIFIC_DAY
import com.todoroo.astrid.data.Task.Companion.HIDE_UNTIL_SPECIFIC_DAY_TIME import com.todoroo.astrid.data.Task.Companion.HIDE_UNTIL_SPECIFIC_DAY_TIME
import com.todoroo.astrid.data.Task.Companion.URGENCY_SPECIFIC_DAY
import com.todoroo.astrid.data.Task.Companion.URGENCY_SPECIFIC_DAY_TIME
import com.todoroo.astrid.helper.UUIDHelper import com.todoroo.astrid.helper.UUIDHelper
import com.todoroo.astrid.service.TaskCreator import com.todoroo.astrid.service.TaskCreator
import net.fortuna.ical4j.model.DateTime import net.fortuna.ical4j.model.DateTime
import net.fortuna.ical4j.model.Parameter import net.fortuna.ical4j.model.Parameter
import net.fortuna.ical4j.model.Property import net.fortuna.ical4j.model.Property
import net.fortuna.ical4j.model.parameter.RelType import net.fortuna.ical4j.model.parameter.RelType
import net.fortuna.ical4j.model.property.DtStart import net.fortuna.ical4j.model.property.*
import net.fortuna.ical4j.model.property.Geo
import net.fortuna.ical4j.model.property.RelatedTo
import net.fortuna.ical4j.model.property.XProperty
import org.tasks.Strings.isNullOrEmpty import org.tasks.Strings.isNullOrEmpty
import org.tasks.caldav.CaldavConverter.DUE_DATE_FORMAT
import org.tasks.caldav.GeoUtils.equalish import org.tasks.caldav.GeoUtils.equalish
import org.tasks.caldav.GeoUtils.toGeo import org.tasks.caldav.GeoUtils.toGeo
import org.tasks.caldav.GeoUtils.toLikeString import org.tasks.caldav.GeoUtils.toLikeString
@ -24,10 +22,13 @@ import org.tasks.data.*
import org.tasks.jobs.WorkManager import org.tasks.jobs.WorkManager
import org.tasks.location.GeofenceApi import org.tasks.location.GeofenceApi
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.time.DateTime.UTC
import timber.log.Timber import timber.log.Timber
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.StringReader import java.io.StringReader
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*
import javax.inject.Inject import javax.inject.Inject
@Suppress("ClassName") @Suppress("ClassName")
@ -58,7 +59,7 @@ class iCalendar @Inject constructor(
place.id = locationDao.insert(place) place.id = locationDao.insert(place)
workManager.reverseGeocode(place) workManager.reverseGeocode(place)
} }
val existing: Location? = locationDao.getGeofences(taskId) val existing = locationDao.getGeofences(taskId)
if (existing == null) { if (existing == null) {
val geofence = Geofence(place.uid, preferences) val geofence = Geofence(place.uid, preferences)
geofence.task = taskId geofence.task = taskId
@ -161,7 +162,8 @@ class iCalendar @Inject constructor(
} }
companion object { companion object {
const val APPLE_SORT_ORDER = "X-APPLE-SORT-ORDER" private val DUE_DATE_FORMAT = SimpleDateFormat("yyyyMMdd", Locale.US)
private const val APPLE_SORT_ORDER = "X-APPLE-SORT-ORDER"
private val IS_PARENT = { r: RelatedTo -> private val IS_PARENT = { r: RelatedTo ->
r.parameters.getParameter<RelType>(Parameter.RELTYPE).let { r.parameters.getParameter<RelType>(Parameter.RELTYPE).let {
it === RelType.PARENT || it == null || it.value.isNullOrBlank() it === RelType.PARENT || it == null || it.value.isNullOrBlank()
@ -172,21 +174,47 @@ class iCalendar @Inject constructor(
x?.name.equals(APPLE_SORT_ORDER, true) x?.name.equals(APPLE_SORT_ORDER, true)
} }
fun Due?.apply(task: com.todoroo.astrid.data.Task) {
task.dueDate = when (this?.date) {
null -> 0
is DateTime -> com.todoroo.astrid.data.Task.createDueDate(
URGENCY_SPECIFIC_DAY_TIME,
getLocal(this)
)
else -> com.todoroo.astrid.data.Task.createDueDate(
URGENCY_SPECIFIC_DAY,
getLocal(this)
)
}
}
fun DtStart?.apply(task: com.todoroo.astrid.data.Task) { fun DtStart?.apply(task: com.todoroo.astrid.data.Task) {
when (this?.date) { task.hideUntil = when (this?.date) {
null -> 0 null -> 0
is DateTime -> task.createHideUntil(HIDE_UNTIL_SPECIFIC_DAY_TIME, date.time) is DateTime -> task.createHideUntil(HIDE_UNTIL_SPECIFIC_DAY_TIME, getLocal(this))
else -> try { else -> task.createHideUntil(HIDE_UNTIL_SPECIFIC_DAY, getLocal(this))
DUE_DATE_FORMAT.parse(value)?.let { }
task.createHideUntil(HIDE_UNTIL_SPECIFIC_DAY, it.time) }
@JvmStatic
fun getLocal(property: DateProperty): Long {
val dateTime = if (property.date is DateTime) {
val dt = property.date as DateTime
org.tasks.time.DateTime(
dt.time,
dt.timeZone ?: if (dt.isUtc) UTC else TimeZone.getDefault()
)
} else {
try {
DUE_DATE_FORMAT.parse(property.value)?.let {
org.tasks.time.DateTime(it)
} }
} catch (e: ParseException) { } catch (e: ParseException) {
Timber.e(e) Timber.e(e)
null null
} }
}?.let {
task.hideUntil = it
} }
return dateTime?.toLocal()?.millis ?: 0
} }
fun fromVtodo(vtodo: String): Task? { fun fromVtodo(vtodo: String): Task? {

@ -21,6 +21,9 @@ object DateTimeUtils {
@JvmStatic @JvmStatic
fun newDateTime(timestamp: Long): DateTime = DateTime(timestamp) fun newDateTime(timestamp: Long): DateTime = DateTime(timestamp)
@JvmStatic
fun newDateTime(timestamp: Long, timeZone: TimeZone): DateTime = DateTime(timestamp, timeZone)
fun Long.toAppleEpoch(): Long = DateTime(this).toAppleEpoch() fun Long.toAppleEpoch(): Long = DateTime(this).toAppleEpoch()
fun Long.toDateTime(): DateTime = DateTime(this) fun Long.toDateTime(): DateTime = DateTime(this)

@ -18,11 +18,11 @@ import java.text.SimpleDateFormat;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Objects; import java.util.Objects;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import net.fortuna.ical4j.model.Date;
import org.tasks.locale.Locale; import org.tasks.locale.Locale;
public class DateTime { public class DateTime {
@ -76,7 +76,7 @@ public class DateTime {
this(timestamp, TimeZone.getDefault()); this(timestamp, TimeZone.getDefault());
} }
private DateTime(long timestamp, TimeZone timeZone) { public DateTime(long timestamp, TimeZone timeZone) {
this.timestamp = timestamp; this.timestamp = timestamp;
this.timeZone = timeZone; this.timeZone = timeZone;
} }
@ -96,12 +96,8 @@ public class DateTime {
return new DateTime(dateValue.year(), dateValue.month(), dateValue.day()); return new DateTime(dateValue.year(), dateValue.month(), dateValue.day());
} }
public static DateTime from(Date date) { public DateTime(Date date) {
return new DateTime(date.getTime(), UTC); this(date.getTime());
}
public static DateTime from(net.fortuna.ical4j.model.DateTime dateTime) {
return new DateTime(dateTime.getTime(), dateTime.getTimeZone());
} }
private DateTime setTime(int hours, int minutes, int seconds, int milliseconds) { private DateTime setTime(int hours, int minutes, int seconds, int milliseconds) {

Loading…
Cancel
Save