66
77use DateInterval ;
88use DateTime ;
9+ use DateTimeZone ;
910use Generator ;
1011use Icinga \Exception \ConfigurationError ;
1112use Icinga \Exception \Http \HttpNotFoundException ;
@@ -80,6 +81,12 @@ class RotationConfigForm extends CompatForm
8081 /** @var int The rotation id */
8182 protected $ rotationId ;
8283
84+ /** @var string The timezone to display the timeline in */
85+ protected $ displayTimezone ;
86+
87+ /** @var string The timezone the schedule is created in */
88+ protected $ scheduleTimezone ;
89+
8390 /**
8491 * Set the label for the submit button
8592 *
@@ -187,11 +194,15 @@ public function hasBeenWiped(): bool
187194 *
188195 * @param int $scheduleId
189196 * @param Connection $db
197+ * @param string $displayTimezone
198+ * @param string $scheduleTimezone
190199 */
191- public function __construct (int $ scheduleId , Connection $ db )
200+ public function __construct (int $ scheduleId , Connection $ db, string $ displayTimezone , string $ scheduleTimezone )
192201 {
193202 $ this ->db = $ db ;
194203 $ this ->scheduleId = $ scheduleId ;
204+ $ this ->displayTimezone = $ displayTimezone ;
205+ $ this ->scheduleTimezone = $ scheduleTimezone ;
195206
196207 $ this ->applyDefaultElementDecorators ();
197208 }
@@ -227,7 +238,11 @@ public function loadRotation(int $rotationId): self
227238 throw new LogicException ('Invalid mode ' );
228239 }
229240
230- $ handoff = DateTime::createFromFormat ('Y-m-d H:i ' , $ rotation ->first_handoff . ' ' . $ time );
241+ $ handoff = DateTime::createFromFormat (
242+ 'Y-m-d H:i ' ,
243+ $ rotation ->first_handoff . ' ' . $ time ,
244+ new DateTimeZone ($ this ->scheduleTimezone )
245+ );
231246 if ($ handoff === false ) {
232247 throw new ConfigurationError ('Invalid date format ' );
233248 }
@@ -258,7 +273,9 @@ public function loadRotation(int $rotationId): self
258273 ->orderBy ('until_time ' , SORT_DESC )
259274 ->first ();
260275 if ($ previousShift !== null ) {
261- $ this ->previousShift = $ previousShift ->until_time ;
276+ $ this ->previousShift = $ previousShift ->until_time ->setTimezone (
277+ new DateTimeZone ($ this ->scheduleTimezone )
278+ );
262279 }
263280
264281 /** @var ?Rotation $newerRotation */
@@ -452,6 +469,9 @@ public function editRotation(int $rotationId): void
452469 ->filter (Filter::equal ('timeperiod.owned_by_rotation_id ' , $ rotationId ));
453470
454471 foreach ($ timeperiodEntries as $ timeperiodEntry ) {
472+ $ timeperiodEntry ->start_time ->setTimezone (new DateTimeZone ($ this ->scheduleTimezone ));
473+ $ timeperiodEntry ->end_time ->setTimezone (new DateTimeZone ($ this ->scheduleTimezone ));
474+
455475 /** @var TimeperiodEntry $timeperiodEntry */
456476 $ rrule = $ timeperiodEntry ->toRecurrenceRule ();
457477 $ shiftDuration = $ timeperiodEntry ->start_time ->diff ($ timeperiodEntry ->end_time );
@@ -819,9 +839,10 @@ protected function assemblePartialDayOptions(FieldsetElement $options): DateTime
819839 ->replaceDecorator ('Description ' , DescriptionDecorator::class, ['class ' => 'description ' ]);
820840
821841 $ selectedFromTime = $ from ->getValue ();
842+ $ nextDayTimeOptions = [];
822843 foreach ($ timeOptions as $ key => $ value ) {
823- unset($ timeOptions [$ key ]); // unset to re-add it at the end of array
824- $ timeOptions [$ key ] = sprintf ( ' %s (%s) ' , $ value, $ this -> translate ( ' Next Day ' )) ;
844+ unset($ timeOptions [$ key ]);
845+ $ nextDayTimeOptions [$ key ] = $ value ;
825846
826847 if ($ selectedFromTime === $ key ) {
827848 break ;
@@ -830,7 +851,9 @@ protected function assemblePartialDayOptions(FieldsetElement $options): DateTime
830851
831852 $ to = $ options ->createElement ('select ' , 'to ' , [
832853 'required ' => true ,
833- 'options ' => $ timeOptions
854+ 'options ' => empty ($ timeOptions )
855+ ? [$ this ->translate ('Next Day ' ) => $ nextDayTimeOptions ]
856+ : [$ this ->translate ('Same Day ' ) => $ timeOptions , $ this ->translate ('Next Day ' ) => $ nextDayTimeOptions ]
834857 ]);
835858 $ options ->registerElement ($ to );
836859
@@ -1226,11 +1249,35 @@ function ($value, $validator) use ($earliestHandoff, $firstHandoff, $latestHando
12261249 (new \IntlDateFormatter (
12271250 \Locale::getDefault (),
12281251 \IntlDateFormatter::MEDIUM ,
1229- \IntlDateFormatter::SHORT
1252+ \IntlDateFormatter::SHORT ,
1253+ $ this ->scheduleTimezone
12301254 ))->format ($ actualFirstHandoff )
12311255 );
12321256 }
1233- })
1257+ }),
1258+ new HtmlElement ('br ' ),
1259+ $ this ->displayTimezone !== $ this ->scheduleTimezone ? DeferredText::create (function () {
1260+ $ ruleGenerator = $ this ->yieldRecurrenceRules (1 );
1261+ if (! $ ruleGenerator ->valid ()) {
1262+ return '' ;
1263+ }
1264+
1265+ $ actualFirstHandoff = $ ruleGenerator ->current ()[0 ]->getStartDate ();
1266+ if ($ actualFirstHandoff < new DateTime ()) {
1267+ return '' ;
1268+ } else {
1269+ return sprintf (
1270+ $ this ->translate ('In your chosen display timezone (%s) this is the %s ' ),
1271+ $ this ->displayTimezone ,
1272+ (new \IntlDateFormatter (
1273+ \Locale::getDefault (),
1274+ \IntlDateFormatter::MEDIUM ,
1275+ \IntlDateFormatter::SHORT ,
1276+ $ this ->displayTimezone
1277+ ))->format ($ actualFirstHandoff )
1278+ );
1279+ }
1280+ }) : new HtmlDocument ()
12341281 ));
12351282 }
12361283
@@ -1293,12 +1340,13 @@ private function parseDateAndTime(?string $date = null, ?string $time = null): D
12931340 }
12941341
12951342 if (! $ format ) {
1296- return ( new DateTime ())-> setTime ( 0 , 0 );
1343+ return new DateTime (' today ' , new DateTimeZone ( $ this -> scheduleTimezone ) );
12971344 }
12981345
1299- $ datetime = DateTime::createFromFormat ($ format , $ expression );
1346+ $ datetime = DateTime::createFromFormat ($ format , $ expression , new DateTimeZone ($ this ->scheduleTimezone ));
1347+
13001348 if ($ datetime === false ) {
1301- $ datetime = ( new DateTime ())-> setTime ( 0 , 0 );
1349+ $ datetime = new DateTime (' today ' , $ this -> scheduleTimezone );
13021350 } elseif ($ time === null ) {
13031351 $ datetime ->setTime (0 , 0 );
13041352 }
@@ -1316,11 +1364,12 @@ private function getTimeOptions(): array
13161364 $ formatter = new \IntlDateFormatter (
13171365 \Locale::getDefault (),
13181366 \IntlDateFormatter::NONE ,
1319- \IntlDateFormatter::SHORT
1367+ \IntlDateFormatter::SHORT ,
1368+ $ this ->scheduleTimezone
13201369 );
13211370
13221371 $ options = [];
1323- $ dt = new DateTime ();
1372+ $ dt = new DateTime (' now ' , new DateTimeZone ( $ this -> scheduleTimezone ) );
13241373 for ($ hour = 0 ; $ hour < 24 ; $ hour ++) {
13251374 for ($ minute = 0 ; $ minute < 60 ; $ minute += 30 ) {
13261375 $ dt ->setTime ($ hour , $ minute );
0 commit comments