From 114271d724112f1835d1a718b42b0f107d8eeb64 Mon Sep 17 00:00:00 2001 From: Ondrej Vlach Date: Wed, 7 Aug 2024 12:39:58 +0200 Subject: [PATCH] feat(services): add duration convertor --- app/Services/Utils/DurationConvertor.php | 64 +++++++++++++++++++ .../Utils/DurationConvertorResult.php | 19 ++++++ .../Services/Utils/DurationConvertorTest.php | 49 ++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 app/Services/Utils/DurationConvertor.php create mode 100644 app/Services/Utils/DurationConvertorResult.php create mode 100644 tests/Unit/Services/Utils/DurationConvertorTest.php diff --git a/app/Services/Utils/DurationConvertor.php b/app/Services/Utils/DurationConvertor.php new file mode 100644 index 0000000..442cb45 --- /dev/null +++ b/app/Services/Utils/DurationConvertor.php @@ -0,0 +1,64 @@ +isEqualTo($startWorkday)) { + throw new \InvalidArgumentException("Start and end workday must be different"); + } + + $workDuration = $duration; + $endDuration = Duration::zero(); + $workDaySeconds = $endWorkday->toSecondOfDay() - $startWorkday->toSecondOfDay(); + + // handle first day + $startDateTime = \DateTimeImmutable::createFromInterface($startTime)->setTime($startWorkday->getHour(), $startWorkday->getMinute()); + $availSecondsFirstDay = $workDaySeconds - ($startTime->getTimestamp() - $startDateTime->getTimestamp()); + + if ($availSecondsFirstDay >= $workDuration->toSeconds()) { + // first day is enough time + $endDuration->plusSeconds($workDaySeconds - $availSecondsFirstDay); + + return new DurationConvertorResult( + false, + $endDuration->plusSeconds($workDuration->toSeconds()) + ); + } else { + $workDuration = $workDuration->minusSeconds($availSecondsFirstDay); + $endDuration = $endDuration->plus(Duration::ofDays(1)); + } + + while ($workDuration->toSeconds() > $workDaySeconds) { + $endDuration = $endDuration->plus(Duration::ofDays(1)); + $workDuration = $workDuration->minusSeconds($workDaySeconds); + } + + return new DurationConvertorResult( + true, + $endDuration->plus($workDuration) + ); + } +} diff --git a/app/Services/Utils/DurationConvertorResult.php b/app/Services/Utils/DurationConvertorResult.php new file mode 100644 index 0000000..19fd4b9 --- /dev/null +++ b/app/Services/Utils/DurationConvertorResult.php @@ -0,0 +1,19 @@ +assertEquals($expectedMinutes, $converter->convertIntoWorkDuration( + Duration::parse($duration), + LocalTime::parse($startWorkday), + LocalTime::parse($endWorkday), + $date + )->duration->toMinutes()); + } + + /** + * @return array> + */ + public static function durationsProvider(): array + { + return [ + [(1.5 + 24) * 60, 'P0DT3H', '08:00', '09:30', '08:00'], // 1.5 hours and one day (half work per day) + [(24 * 2 + 1) * 60, 'P0DT3H', '08:00', '09:00', '08:00'], // 1 hour and two days (1/3 per day) + [3 * 24 * 60 + 30, 'P0DT3H30M', '08:00', '09:00', '8:00'], // full 3 days and 30M + [3 * 60, 'P0DT3H', '08:00', '16:00', '08:00'], // 3 hours + [4 * 60, 'P0DT4H', '08:00', '16:00', '08:00'], // 4 hours + [8 * 60, 'P0DT8H', '08:00', '16:00', '08:00'], // 8 hours (one full day) + [24 * 60 + 2, 'P0DT8H2M', '08:00', '16:00', '08:00'], // 8 hours and 2 minutes (one full day and 2 minutes) + [24 * 60 + 1, 'P0DT0H2M', '08:00', '16:00', '15:59'] // 1 minute first day, one minute second day because startTime + ]; + } +}