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 ;
@@ -221,6 +222,7 @@ public function onCalendarObjectCreate(array $objectData):void {
221222 if (!$ vcalendar ) {
222223 return ;
223224 }
225+ $ calendarTimeZone = $ this ->getCalendarTimeZone ((int ) $ objectData ['calendarid ' ]);
224226
225227 $ vevents = $ this ->getAllVEventsFromVCalendar ($ vcalendar );
226228 if (count ($ vevents ) === 0 ) {
@@ -249,7 +251,7 @@ public function onCalendarObjectCreate(array $objectData):void {
249251 continue ;
250252 }
251253
252- $ alarms = $ this ->getRemindersForVAlarm ($ valarm , $ objectData ,
254+ $ alarms = $ this ->getRemindersForVAlarm ($ valarm , $ objectData , $ calendarTimeZone ,
253255 $ eventHash , $ alarmHash , true , true );
254256 $ this ->writeRemindersToDatabase ($ alarms );
255257 }
@@ -306,6 +308,16 @@ public function onCalendarObjectCreate(array $objectData):void {
306308
307309 try {
308310 $ triggerTime = $ valarm ->getEffectiveTriggerTime ();
311+ /**
312+ * @psalm-suppress DocblockTypeContradiction
313+ * https://github.com/vimeo/psalm/issues/9244
314+ */
315+ if ($ triggerTime ->getTimezone () === false || $ triggerTime ->getTimezone ()->getName () === 'UTC ' ) {
316+ $ triggerTime = new DateTimeImmutable (
317+ $ triggerTime ->format ('Y-m-d H:i:s ' ),
318+ $ calendarTimeZone
319+ );
320+ }
309321 } catch (InvalidDataException $ e ) {
310322 continue ;
311323 }
@@ -324,7 +336,7 @@ public function onCalendarObjectCreate(array $objectData):void {
324336 continue ;
325337 }
326338
327- $ alarms = $ this ->getRemindersForVAlarm ($ valarm , $ objectData , $ masterHash , $ alarmHash , $ isRecurring , false );
339+ $ alarms = $ this ->getRemindersForVAlarm ($ valarm , $ objectData , $ calendarTimeZone , $ masterHash , $ alarmHash , $ isRecurring , false );
328340 $ this ->writeRemindersToDatabase ($ alarms );
329341 $ processedAlarms [] = $ alarmHash ;
330342 }
@@ -363,6 +375,7 @@ public function onCalendarObjectDelete(array $objectData):void {
363375 /**
364376 * @param VAlarm $valarm
365377 * @param array $objectData
378+ * @param DateTimeZone $calendarTimeZone
366379 * @param string|null $eventHash
367380 * @param string|null $alarmHash
368381 * @param bool $isRecurring
@@ -371,6 +384,7 @@ public function onCalendarObjectDelete(array $objectData):void {
371384 */
372385 private function getRemindersForVAlarm (VAlarm $ valarm ,
373386 array $ objectData ,
387+ DateTimeZone $ calendarTimeZone ,
374388 string $ eventHash = null ,
375389 string $ alarmHash = null ,
376390 bool $ isRecurring = false ,
@@ -386,6 +400,16 @@ private function getRemindersForVAlarm(VAlarm $valarm,
386400 $ isRelative = $ this ->isAlarmRelative ($ valarm );
387401 /** @var DateTimeImmutable $notificationDate */
388402 $ notificationDate = $ valarm ->getEffectiveTriggerTime ();
403+ /**
404+ * @psalm-suppress DocblockTypeContradiction
405+ * https://github.com/vimeo/psalm/issues/9244
406+ */
407+ if ($ notificationDate ->getTimezone () === false || $ notificationDate ->getTimezone ()->getName () === 'UTC ' ) {
408+ $ notificationDate = new DateTimeImmutable (
409+ $ notificationDate ->format ('Y-m-d H:i:s ' ),
410+ $ calendarTimeZone
411+ );
412+ }
389413 $ clonedNotificationDate = new \DateTime ('now ' , $ notificationDate ->getTimezone ());
390414 $ clonedNotificationDate ->setTimestamp ($ notificationDate ->getTimestamp ());
391415
@@ -471,6 +495,7 @@ private function deleteOrProcessNext(array $reminder,
471495 $ vevents = $ this ->getAllVEventsFromVCalendar ($ vevent ->parent );
472496 $ recurrenceExceptions = $ this ->getRecurrenceExceptionFromListOfVEvents ($ vevents );
473497 $ now = $ this ->timeFactory ->getDateTime ();
498+ $ calendarTimeZone = $ this ->getCalendarTimeZone ((int ) $ reminder ['calendar_id ' ]);
474499
475500 try {
476501 $ iterator = new EventIterator ($ vevents , $ reminder ['uid ' ]);
@@ -517,7 +542,7 @@ private function deleteOrProcessNext(array $reminder,
517542 $ alarms = $ this ->getRemindersForVAlarm ($ valarm , [
518543 'calendarid ' => $ reminder ['calendar_id ' ],
519544 'id ' => $ reminder ['object_id ' ],
520- ], $ reminder ['event_hash ' ], $ alarmHash , true , false );
545+ ], $ calendarTimeZone , $ reminder ['event_hash ' ], $ alarmHash , true , false );
521546 $ this ->writeRemindersToDatabase ($ alarms );
522547
523548 // Abort generating reminders after creating one successfully
@@ -825,4 +850,26 @@ private function getEffectiveRecurrenceIdOfVEvent(VEvent $vevent):int {
825850 private function isRecurring (VEvent $ vevent ):bool {
826851 return isset ($ vevent ->RRULE ) || isset ($ vevent ->RDATE );
827852 }
853+
854+ /**
855+ * @param int $calendarid
856+ *
857+ * @return DateTimeZone
858+ */
859+ private function getCalendarTimeZone (int $ calendarid ): DateTimeZone {
860+ $ calendarInfo = $ this ->caldavBackend ->getCalendarById ($ calendarid );
861+ $ tzProp = '{urn:ietf:params:xml:ns:caldav}calendar-timezone ' ;
862+ if (!isset ($ calendarInfo [$ tzProp ])) {
863+ // Defaulting to UTC
864+ return new DateTimeZone ('UTC ' );
865+ }
866+ // This property contains a VCALENDAR with a single VTIMEZONE
867+ /** @var string $timezoneProp */
868+ $ timezoneProp = $ calendarInfo [$ tzProp ];
869+ /** @var VObject\Component\VCalendar $vtimezoneObj */
870+ $ vtimezoneObj = VObject \Reader::read ($ timezoneProp );
871+ /** @var VObject\Component\VTimeZone $vtimezone */
872+ $ vtimezone = $ vtimezoneObj ->VTIMEZONE ;
873+ return $ vtimezone ->getTimeZone ();
874+ }
828875}
0 commit comments