65 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			65 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
declare(strict_types=1);
 | 
						|
 | 
						|
namespace App\Services\Utils;
 | 
						|
 | 
						|
use Brick\DateTime\Duration;
 | 
						|
use Brick\DateTime\LocalTime;
 | 
						|
 | 
						|
/*
 | 
						|
 * Converts given dates and times into a Duration object.
 | 
						|
 */
 | 
						|
class DurationConvertor
 | 
						|
{
 | 
						|
    public function __construct()
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Convert a given duration into working hours considering the given start and end workday. Duration is calculated from startWorkday
 | 
						|
     * @param Duration $duration
 | 
						|
     * @param LocalTime $startWorkday
 | 
						|
     * @param LocalTime $endWorkday
 | 
						|
     * @param \DateTimeInterface $startTime
 | 
						|
     * @return DurationConvertorResult
 | 
						|
     */
 | 
						|
    public function convertIntoWorkDuration(Duration $duration, LocalTime $startWorkday, LocalTime $endWorkday, \DateTimeInterface $startTime): DurationConvertorResult
 | 
						|
    {
 | 
						|
        if ($endWorkday->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)
 | 
						|
        );
 | 
						|
    }
 | 
						|
}
 |