简体   繁体   中英

Get total hours from start_time and end_time for each date PHP?

I am using below code to find out correct total hours but it is giving wrong results:- Using getSortedDays to sort my array Using addTotalAttendedHours to add total and add it into total attended hours,I have tried all possible methods of time and none of them are working. Even I tried removing abs and round but nothing is helping

<?php

declare(strict_types=1);

$data = [
  '2020-07-14' => 
  [
    [
      'start_time' => '14:15:00',
      'end_time' => '17:45:00',
    ],[
      'start_time' => '14:30:00',
      'end_time' => '17:30:00',
    ],[
      'start_time' => '14:30:00',
      'end_time' => '17:30:00',
    ],
  ],
  '2020-07-15' => [
    [
      'start_time' => '13:30:00',
      'end_time' => '17:00:00',
    ],[
      'start_time' => '09:00:00',
      'end_time' => '14:00:00',
    ],
  ],
];

function getSortedDays(array $days): array {
    return array_map(function (array $day) {
       array_multisort(array_column($day, 'start_time'), SORT_ASC, $day);
       
       return $day;
    }, $days);
}

function addTotalAttendedHours(array $days): array {
    $sortedDays = getSortedDays($days);
    
    $days = array_map(function (array $day) {
        $sum = (new DateTime())->setTimestamp(0);
        $previousEnd = null;
        
        foreach ($day as $time) {
            $currentStart = new DateTimeImmutable($time['start_time']);
            $currentEnd = new DateTimeImmutable($time['end_time']);
            
            $sum->add($currentStart->diff($currentEnd));
            
            if ($previousEnd !== null && $currentStart < $previousEnd) {
                $sum->sub($currentStart->diff($previousEnd));
            }
            
            $previousEnd = $currentEnd;
        }
        
        $attendedSeconds = $sum->getTimestamp();
        $day['total_attended_hours'] = sprintf(
            '%02u:%02u:%02u',
            $attendedSeconds / 60 / 60,
            ($attendedSeconds / 60) % 60,
            $attendedSeconds % 60
        );
        
        return $day;
    }, $sortedDays);
    
    return $days;
}
echo "<pre>";
print_r(addTotalAttendedHours($data));
?>

Result

Array
(
    [2020-07-14] => Array
        (
            [0] => Array
                (
                    [start_time] => 14:15:00
                    [end_time] => 17:45:00
                )

            [1] => Array
                (
                    [start_time] => 14:30:00
                    [end_time] => 17:30:00
                )

            [2] => Array
                (
                    [start_time] => 14:30:00
                    [end_time] => 17:30:00
                )

            [total_attended_hours] => 03:15:00  //It should be 03:30:00
        )

    [2020-07-15] => Array
        (
            [0] => Array
                (
                    [start_time] => 09:00:00
                    [end_time] => 14:00:00
                )

            [1] => Array
                (
                    [start_time] => 13:30:00
                    [end_time] => 17:00:00
                )

            [total_attended_hours] => 08:00:00
        )

)

Using above code I am getting wrong total_attended_hours where for date 2020-07-14 the result should be 03:30:00 but it is giving 03:15:00

For the first day you have these time ranges:
14:15 – 17:45
14:30 – 17:30
14:30 – 17:30

And you are doing this:

  • calculating the diff for the first range: 3:30
  • calculating the diff for the second range (3:00) and adding it: 3:30 + 3:00 = 06:30
  • because the start of the second range is before the previous end, you are subtracting the diff between them. the diff between 14:30 and 17:45 is 3:15, so 6:30 - 3:15 = 3:15
  • but the second range already ends at 17:30, so you are missing the 15 minutes between 17:30 and 17:45.

You could change the subtracting line to:

$sum->sub($currentStart->diff(min($currentEnd, $previousEnd)));

This way you wouldn't subtract too much anymore, because you would subtract only the diff of the overlapping part until the minimum of current and previous end.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM