|
|
- <?php
-
- namespace App\Services;
-
- use App\DTO\DurationResult;
- use App\Enums\DurationModifier;
- use App\Traits\Invokable;
- use DateInterval;
- use DatePeriod;
- use DateTime;
- use DateTimeImmutable;
- use ValueError;
- use TypeError;
- use Illuminate\Contracts\Container\BindingResolutionException;
- use Spatie\LaravelData\Exceptions\CannotCreateData;
- use Spatie\LaravelData\Exceptions\CannotSetComputedValue;
-
- /** @package App\Services */
- class CalculateDuration
- {
- const WEEKDAYS = [1, 2, 3, 4, 5];
-
- /**
- * @param DateTime $start
- * @param DateTime $end
- *
- * @return void
- */
- public function __construct(
- protected DateTimeImmutable $start,
- protected DateTimeImmutable $end
- ) {
- }
-
- /**
- * @param DurationModifier $durationModifier
- *
- * @return DurationResult
- *
- * @throws ValueError
- * @throws TypeError
- * @throws BindingResolutionException
- * @throws CannotCreateData
- * @throws CannotSetComputedValue
- */
- public function result(DurationModifier $durationModifier = DurationModifier::None): DurationResult
- {
- $days = $this->calculateDuration();
- $weekDays = $this->calculateDuration(true);
- $weeks = $this->calculateDurationWeeks();
-
- $durationModifierInDays = $durationModifier->durationModiferInDays();
-
- return new DurationResult(
- days: $days * $durationModifierInDays,
- weeks: $weeks * ($durationModifier === DurationModifier::None ? 1 : $durationModifierInDays * 7),
- weekDays: $weekDays * $durationModifierInDays,
- );
- }
-
- /**
- * @param string $intervalDuration
- * @param bool $skipWeekends
- *
- * @return int
- */
- protected function calculateDuration(bool $skipWeekends = false): int
- {
- $interval = new DateInterval('P1D');
-
- $period = new DatePeriod(
- $this->start,
- $interval,
- $this->end->add($interval),
- );
-
- $intervalCount = 0;
- foreach ($period as $date) {
- if ($skipWeekends && !in_array($date->format('N'), self::WEEKDAYS)) {
- continue;
- }
-
- $intervalCount++;
- }
-
- return $intervalCount;
- }
-
- /**
- * @return int
- */
- protected function calculateDurationWeeks(): int
- {
- return floor($this->start->diff($this->end)->days / 7);
- }
- }
|