Here's a more complete solution using CarbonPeriod.
Carbon Calculate hours in an interval from a period
<?php
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Carbon\CarbonInterval;
class PeriodInterval {
public function hoursIn() {
/**
* Time Periods
*/
$periods = [
'day' => [
'08:00:00',
'18:00:00'
],
'night' => [
'18:00:00',
'08:00:00'
],
'lunch' => [
'11:00:00',
'14:00:00'
]
];
/**
* Time Intervals
*/
$intervals = [
'parking' => [
'John Doe' => [
Carbon::createFromFormat('Y-m-d H:i:s', '2018-12-10 07:00:00'),
Carbon::createFromFormat('Y-m-d H:i:s', '2018-12-10 09:00:00')
],
'Jane Doe' => [
Carbon::createFromFormat('Y-m-d H:i:s', '2018-12-10 08:00:00'),
Carbon::createFromFormat('Y-m-d H:i:s', '2018-12-10 09:00:00')
],
'John Hope' => [
Carbon::createFromFormat('Y-m-d H:i:s', '2018-12-10 11:00:00'),
Carbon::createFromFormat('Y-m-d H:i:s', '2018-12-10 13:00:00')
],
'Jane Hope' => [
Carbon::createFromFormat('Y-m-d H:i:s', '2018-12-10 18:00:00'),
Carbon::createFromFormat('Y-m-d H:i:s', '2018-12-10 19:00:00')
]
]
];
/**
* Hours for Interval in Period
*/
function hoursForIntervalInPeriod(array $period, array $interval) {
$Period = new CarbonPeriod(array_shift($interval)->toDateTimeString(), '1 hour', array_pop($interval)->toDateTimeString());
return $Period->filter(function($date) use ($period) {
$period_starts = Carbon::createFromFormat('Y-m-d H:i:s', $date->format('Y-m-d') . ' ' . array_shift($period));
$period_ends = Carbon::createFromFormat('Y-m-d H:i:s', $date->format('Y-m-d') . ' ' . array_pop($period));
// Normal Period
if ($period_starts < $period_ends) {
return ($date >= $period_starts && $date < $period_ends);
}
// Inverted Period (Overnight)
if ($period_starts > $period_ends) {
return ($date >= $period_starts || $date < $period_ends);
}
return false;
})->count();
}
/**
* Map Everything
*/
$hours = array_map(function($interval, $interval_key) use ($periods) {
return array_map(function ($period, $period_key) use ($interval, $interval_key) {
return [ $interval_key . ucfirst($period_key) => array_map(function($interval_item, $interval_item_key) use ($period) {
/**
* Calculate Total Hours
*/
$total_hours = hoursForIntervalInPeriod($period, $interval_item);
return [ $interval_item_key => $total_hours ];
}, $interval, array_keys($interval)) ];
}, $periods, array_keys($periods));
}, $intervals, array_keys($intervals));
return $hours;
}
}