bookings->find_by_id( $booking_id ); if ( null === $booking ) { throw new DomainException( 'booking.not_found', 'Booking not found.' ); } $utc = new DateTimeZone( 'UTC' ); try { $start = ( new DateTimeImmutable( $start_iso ) )->setTimezone( $utc ); } catch ( \Exception $e ) { throw new DomainException( 'booking.start_invalid', 'Start date and time are invalid.' ); } $end = null; if ( '' !== trim( $end_iso ) ) { try { $end = ( new DateTimeImmutable( $end_iso ) )->setTimezone( $utc ); } catch ( \Exception $e ) { throw new DomainException( 'booking.end_invalid', 'End date and time are invalid.' ); } } $duration = null !== $end ? $end->getTimestamp() - $start->getTimestamp() : $booking->end_utc()->getTimestamp() - $booking->start_utc()->getTimestamp(); if ( $duration < 1 ) { throw new DomainException( 'booking.range', 'End must be after start.' ); } $end_utc = $start->modify( '+' . $duration . ' seconds' ); $buf_before = $booking->start_utc()->getTimestamp() - $booking->buffer_start_utc()->getTimestamp(); $buf_after = $booking->buffer_end_utc()->getTimestamp() - $booking->end_utc()->getTimestamp(); $buffer_start = $start->modify( '-' . max( 0, $buf_before ) . ' seconds' ); $buffer_end = $end_utc->modify( '+' . max( 0, $buf_after ) . ' seconds' ); return $this->reschedule->handle( $booking_id, $start, $end_utc, $buffer_start, $buffer_end, $start ); } }