skip to Main Content

To calculate working hours, I need to separately calculate the number of hours that the user worked during working hours(09:00 – 17:00) and outside of working hours (overtime) and return their sum.

For example, the user worked from 2023-01-23 15:00 to 2023-01-23 22:00, which is 2023-01-23 15:00 to 2023-01-23 17:00 in the working hours and 2023-01-23 17:00 to
2023-01-23 22:00 is overtime.

Now, how can I find out how much of the user’s working hours are within the range of 9:00 to 17:00 and how much is outside the hours?

foreach ($timeSheets as $key => $time) {
    if ($time->is_in == 1) {
        $time_in = new Carbon($time->event_at);
        $time_out = new Carbon($timeSheets[$key + 1]->event_at);
        [$time_in, $time_out] = $this->getTimeZoneName($bill->BillingRateTimezone->timezone, $time_in, $time_out);
        // period of his/her work time
        $start_time = $time_in->format("H:i");
        $end_time = $time_out->format("H:i");

        // How can I calculate how much of user work time is between 9:00-17:00 and how much is outside of this  ??
                        
        $sumOfInside = "?";
        $sumOfOutside = "?";
    }
}

2

Answers


  1. You can use https://github.com/kylekatarnls/business-time

    For instance with the method diffInBusinessMinutes you get a number of minutes in, and with Carbon diffInMinutes, you get the total, so minutes out are the first subtracted from the total.

    Login or Signup to reply.
  2. There’s probably a better way to go around it but a bunch of conditionals to cover every case could work.

    Case 1:

             [-------------]                                         user hours  
                             [------------------]                    9:00 to 17:00  
      |    |    |    |    |    |    |    |    |    |    |    |    |  
      0    2    4    6    8    10   12   14   16   18   20   22   24  
    

    Case 2:

                                                  [-----------]      user hours  
                             [------------------]                    9:00 to 17:00  
      |    |    |    |    |    |    |    |    |    |    |    |    |  
      0    2    4    6    8    10   12   14   16   18   20   22   24  
    

    Case 3:

                               [-------------]                       user hours  
                             [------------------]                    9:00 to 17:00  
      |    |    |    |    |    |    |    |    |    |    |    |    |  
      0    2    4    6    8    10   12   14   16   18   20   22   24  
    

    Case 4:

                       [-------------]                               user hours  
                             [------------------]                    9:00 to 17:00  
      |    |    |    |    |    |    |    |    |    |    |    |    |  
      0    2    4    6    8    10   12   14   16   18   20   22   24  
    

    Case 5:

                                     [-------------]                 user hours  
                             [------------------]                    9:00 to 17:00  
      |    |    |    |    |    |    |    |    |    |    |    |    |  
      0    2    4    6    8    10   12   14   16   18   20   22   24  
    

    Case 6:

                        [--------------------------]                 user hours  
                             [------------------]                    9:00 to 17:00  
      |    |    |    |    |    |    |    |    |    |    |    |    |  
      0    2    4    6    8    10   12   14   16   18   20   22   24  
    

    Using Carbon ‘s diff method can be very helpful for this, but since datetimes are needed, Carbon::today() (or simply today() if you want to use the laravel helper) can give us a date with it’s time at 00:00:00, which is perfect for our needs. As for getting the sum, we can incrementally add to a couple of instances of CarbonInterval.

    $inside_working_time = CarbonInterval::make('0h 0m 0s');
    $outside_working_time = CarbonInterval::make('0h 0m 0s');
    
    // start and end of work day
    $_9 = Carbon::today()->add('9h');
    $_17 = Carbon::today()->add('17h');
    foreach (...) {
        ...
        $user_start = Carbon::today()->add($time_in->format('Hh im'));
        $user_end = Carbon::today()->add($time_out->format('Hh im'));
    
        $inside_working_interval = CarbonInterval::make('0h 0m 0s');
        $outside_working_interval = CarbonInterval::make('0h 0m 0s');
    
        // Case 1
        if ($user_start->lessThan($_9) && $user_end->lessThanOrEqualTo($_9)) {
            $outside_working_interval->add($user_start->diff($user_end));
        }
        // Case 2
        elseif ($user_start->greaterThanOrEqualTo($_17) && $user_end->greaterThan($_17)) {
            $outside_working_interval->add($user_start->diff($user_end));
        }
        // Case 3
        elseif ($user_start->greaterThanOrEqualTo($_9) && $user_end->lessThanOrEqualTo($_17)) {
            $inside_working_interval->add($user_start->diff($user_end));
        }
        // Case 4
        elseif ($user_start->lessThan($_9) && $user_end->between($_9, $_17)) {
            $inside_working_interval->add($_9->diff($user_end));
            $outside_working_interval->add($user_start->diff($_9));
        }
        // Case 5
        elseif ($user_start->between($_9, $_17) && $user_end->greaterThan($_17)) {
            $inside_working_interval->add($user_start->diff($_17));
            $outside_working_interval->add($_17->diff($user_end));
        }
        // Case 6
        elseif ($user_start->lessThan($_9) && $user_end->greaterThan($_17)) {
            $inside_working_interval->add($_9->diff($_17));
            $outside_working_interval->add($user_start->diff($_9);
            $outside_working_interval->add($_17->diff($user_end));
        }
    
        $inside_working_time->add($inside_working_interval);
        $outside_working_time->add($outside_working_interval);
    }
    

    And then you can either print out the interval with the forHumans() method or get the total hours and minutes.

    $inside_working_time->forHumans() // (string) 'X hours and Y minutes'
    
    $inside_working_time->cascade()->h // (int) hours
    $inside_working_time->cascade()->i // (int) the minutes that remain
    
    $inside_working_time->totalHours // (float) hours expressed as decimal (for example 7.333 hours for 7h 20m
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search