Skip to content

Commit 77f6ed9

Browse files
ChristophWurstMichaIng
authored andcommitted
fix(caldav): Fix reminder timezone drift for all-day events
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
1 parent 3a06d33 commit 77f6ed9

2 files changed

Lines changed: 235 additions & 14 deletions

File tree

apps/dav/lib/CalDAV/Reminder/ReminderService.php

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
namespace OCA\DAV\CalDAV\Reminder;
3333

3434
use DateTimeImmutable;
35+
use DateTimeZone;
3536
use OCA\DAV\CalDAV\CalDavBackend;
3637
use OCA\DAV\Connector\Sabre\Principal;
3738
use OCP\AppFramework\Utility\ITimeFactory;
@@ -205,6 +206,7 @@ public function onCalendarObjectCreate(array $objectData):void {
205206
if (!$vcalendar) {
206207
return;
207208
}
209+
$calendarTimeZone = $this->getCalendarTimeZone((int) $objectData['calendarid']);
208210

209211
$vevents = $this->getAllVEventsFromVCalendar($vcalendar);
210212
if (count($vevents) === 0) {
@@ -233,7 +235,7 @@ public function onCalendarObjectCreate(array $objectData):void {
233235
continue;
234236
}
235237

236-
$alarms = $this->getRemindersForVAlarm($valarm, $objectData,
238+
$alarms = $this->getRemindersForVAlarm($valarm, $objectData, $calendarTimeZone,
237239
$eventHash, $alarmHash, true, true);
238240
$this->writeRemindersToDatabase($alarms);
239241
}
@@ -286,6 +288,16 @@ public function onCalendarObjectCreate(array $objectData):void {
286288

287289
try {
288290
$triggerTime = $valarm->getEffectiveTriggerTime();
291+
/**
292+
* @psalm-suppress DocblockTypeContradiction
293+
* https://github.com/vimeo/psalm/issues/9244
294+
*/
295+
if ($triggerTime->getTimezone() === false || $triggerTime->getTimezone()->getName() === 'UTC') {
296+
$triggerTime = new DateTimeImmutable(
297+
$triggerTime->format('Y-m-d H:i:s'),
298+
$calendarTimeZone
299+
);
300+
}
289301
} catch (InvalidDataException $e) {
290302
continue;
291303
}
@@ -304,7 +316,7 @@ public function onCalendarObjectCreate(array $objectData):void {
304316
continue;
305317
}
306318

307-
$alarms = $this->getRemindersForVAlarm($valarm, $objectData, $masterHash, $alarmHash, $isRecurring, false);
319+
$alarms = $this->getRemindersForVAlarm($valarm, $objectData, $calendarTimeZone, $masterHash, $alarmHash, $isRecurring, false);
308320
$this->writeRemindersToDatabase($alarms);
309321
$processedAlarms[] = $alarmHash;
310322
}
@@ -343,6 +355,7 @@ public function onCalendarObjectDelete(array $objectData):void {
343355
/**
344356
* @param VAlarm $valarm
345357
* @param array $objectData
358+
* @param DateTimeZone $calendarTimeZone
346359
* @param string|null $eventHash
347360
* @param string|null $alarmHash
348361
* @param bool $isRecurring
@@ -351,6 +364,7 @@ public function onCalendarObjectDelete(array $objectData):void {
351364
*/
352365
private function getRemindersForVAlarm(VAlarm $valarm,
353366
array $objectData,
367+
DateTimeZone $calendarTimeZone,
354368
string $eventHash = null,
355369
string $alarmHash = null,
356370
bool $isRecurring = false,
@@ -366,6 +380,16 @@ private function getRemindersForVAlarm(VAlarm $valarm,
366380
$isRelative = $this->isAlarmRelative($valarm);
367381
/** @var DateTimeImmutable $notificationDate */
368382
$notificationDate = $valarm->getEffectiveTriggerTime();
383+
/**
384+
* @psalm-suppress DocblockTypeContradiction
385+
* https://github.com/vimeo/psalm/issues/9244
386+
*/
387+
if ($notificationDate->getTimezone() === false || $notificationDate->getTimezone()->getName() === 'UTC') {
388+
$notificationDate = new DateTimeImmutable(
389+
$notificationDate->format('Y-m-d H:i:s'),
390+
$calendarTimeZone
391+
);
392+
}
369393
$clonedNotificationDate = new \DateTime('now', $notificationDate->getTimezone());
370394
$clonedNotificationDate->setTimestamp($notificationDate->getTimestamp());
371395

@@ -451,6 +475,7 @@ private function deleteOrProcessNext(array $reminder,
451475
$vevents = $this->getAllVEventsFromVCalendar($vevent->parent);
452476
$recurrenceExceptions = $this->getRecurrenceExceptionFromListOfVEvents($vevents);
453477
$now = $this->timeFactory->getDateTime();
478+
$calendarTimeZone = $this->getCalendarTimeZone((int) $reminder['calendar_id']);
454479

455480
try {
456481
$iterator = new EventIterator($vevents, $reminder['uid']);
@@ -800,4 +825,26 @@ private function getEffectiveRecurrenceIdOfVEvent(VEvent $vevent):int {
800825
private function isRecurring(VEvent $vevent):bool {
801826
return isset($vevent->RRULE) || isset($vevent->RDATE);
802827
}
828+
829+
/**
830+
* @param int $calendarid
831+
*
832+
* @return DateTimeZone
833+
*/
834+
private function getCalendarTimeZone(int $calendarid): DateTimeZone {
835+
$calendarInfo = $this->caldavBackend->getCalendarById($calendarid);
836+
$tzProp = '{urn:ietf:params:xml:ns:caldav}calendar-timezone';
837+
if (!isset($calendarInfo[$tzProp])) {
838+
// Defaulting to UTC
839+
return new DateTimeZone('UTC');
840+
}
841+
// This property contains a VCALENDAR with a single VTIMEZONE
842+
/** @var string $timezoneProp */
843+
$timezoneProp = $calendarInfo[$tzProp];
844+
/** @var VObject\Component\VCalendar $vtimezoneObj */
845+
$vtimezoneObj = VObject\Reader::read($timezoneProp);
846+
/** @var VObject\Component\VTimeZone $vtimezone */
847+
$vtimezone = $vtimezoneObj->VTIMEZONE;
848+
return $vtimezone->getTimeZone();
849+
}
803850
}

0 commit comments

Comments
 (0)