3232namespace OCA \DAV \CalDAV \Reminder ;
3333
3434use DateTimeImmutable ;
35+ use DateTimeZone ;
3536use OCA \DAV \CalDAV \CalDavBackend ;
3637use OCA \DAV \Connector \Sabre \Principal ;
3738use 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