@@ -298,7 +298,8 @@ protected function normalize_exceptions(array $event) : array {
298
298
// granularity based on frequencty, so that RRULE can properly parse
299
299
// exception times.
300
300
$ aligned = array_map (function ($ exception ) use ($ event , $ rules ) {
301
- return $ this ->align_time ($ exception , $ event ['start ' ], $ rules ['frequency ' ]);
301
+ $ event_start_with_override = $ this ->get_event_start_with_overrides ($ exception , $ event );
302
+ return $ this ->align_time ($ exception , $ event_start_with_override , $ rules ['frequency ' ]);
302
303
}, $ normalized );
303
304
304
305
// Filter out empty values, which could have been returned by parsing a
@@ -342,4 +343,51 @@ public function align_time(string $dt, string $start, string $freq) {
342
343
$ start_str = gmdate ($ start_fmt , strtotime ($ start ) ?: 0 );
343
344
return date_create_immutable ($ dt_str . $ start_str );
344
345
}
346
+
347
+ /**
348
+ * Given a target occurrence date string and an event, get the start date and time
349
+ * string, with any applicable override applied.
350
+ *
351
+ * @param string $dt The target event occurrence date string, formatted Y-m-d H:i:s
352
+ * @param array $event The event data array, including recurrence data
353
+ *
354
+ * @return string The start date of the event on the target date, possibly with the
355
+ * time overridden
356
+ */
357
+ public function get_event_start_with_overrides (string $ dt , array $ event ) {
358
+ // Start with the original start datetime
359
+ $ start = $ event ['start ' ];
360
+ $ overrides = $ event ['recurrence ' ]['overrides ' ] ?? [];
361
+
362
+ if ($ overrides ) {
363
+ $ days_of_week = [
364
+ 1 => 'MO ' ,
365
+ 2 => 'TU ' ,
366
+ 3 => 'WE ' ,
367
+ 4 => 'TH ' ,
368
+ 5 => 'FR ' ,
369
+ 6 => 'SA ' ,
370
+ 7 => 'SU ' ,
371
+ ];
372
+ $ dt_object = \DateTime::createFromFormat ('Y-m-d H:i:s ' , $ dt );
373
+ $ dt_day_of_week = $ dt_object ->format ('N ' );
374
+ $ dt_day_of_week_code = $ days_of_week [$ dt_day_of_week ];
375
+ $ applicable_overrides = array_values (
376
+ array_filter (
377
+ $ overrides ,
378
+ function ($ override ) use ($ dt_day_of_week_code ) {
379
+ return in_array ($ dt_day_of_week_code , $ override ['BYDAY ' ] ?? []);
380
+ }
381
+ )
382
+ );
383
+
384
+ // Change the start datetime based on the override we found
385
+ if ($ applicable_overrides ) {
386
+ $ override_time = $ applicable_overrides [0 ]['start ' ];
387
+ $ start = $ dt_object ->format ('Y-m-d ' ) . ' ' . $ override_time ;
388
+ }
389
+ }
390
+
391
+ return $ start ;
392
+ }
345
393
}
0 commit comments