Jump to content

Getting Total Hours from Array


Moorcam

Recommended Posts

Hey all,

 

I am trying to get the total number of hours from an array as follows:

<?php
if(isset($_POST['calculate']) != ""){
class times_counter {

    private $hou = 0;
    private $min = 0;
    private $sec = 0;
    private $totaltime = '00:00:00';

    public function __construct($times){
        
        if(is_array($times)){

            $length = sizeof($times);

            for($x=0; $x <= $length; $x++){
                    $split = explode(":", @$times[$x]); 
                    $this->hou += @$split[0];
                    $this->min += @$split[1];
                    $this->sec += @$split[2];
            }

            $seconds = $this->sec % 60;
            $minutes = $this->sec / 60;
            $minutes = (integer)$minutes;
            $minutes += $this->min;
            $hours = $minutes / 60;
            $minutes = $minutes % 60;
            $hours = (integer)$hours;
            $hours += $this->hou % 24;
            $this->totaltime = $hours.":".$minutes.":".$seconds;
        }
    }

    public function get_total_time(){
        return $this->totaltime;
    }

}
$times = array(
    '02:00:00',
    '12:15:00'
);

$counter = new times_counter($times);
echo $counter->get_total_time();
?>

This works fine as is with times just placed inside the array. However, I need to get the times from an object, such as:

$times = array(
    $time1,
    $time2
);

This will not work because it throws an error - Warning: explode() expects parameter 2 to be string, object given

The warning is thrown from here:

$split = explode(":", @$times[$x]);

Is there a way for me to add all the hours to get a total of the hours?

For example:

$time1 = 12:00

$time2 = 12:00

Total Hours = 24:00 ,<- This is what I am after.

 

Thanks in advance,

Link to comment
Share on other sites

What type of objects? What is their structure? Public properties,methods? Give us a clue.

 

Also, the addition process would be easier with DateTime objects

$times = [ '05:30:00', '03:15:00', '19:45:00' ];

$now = new DateTime();
$dt1 = clone $now;

foreach ($times as $t) {
	$di = new DateInterval("P0000-00-00T$t");
	$dt1->add($di);
	
}

$total_time = $now->diff($dt1);

echo $total_time->format('%d days %h hrs %i mins');  //--> 1 days 4 hrs 30 mins
Link to comment
Share on other sites

Do you plan to use this for arrays or objects? Pick one and code for it. You can always convert one to the other to make the class flexible.

 

 

$length = sizeof($times);

for($x=0; $x <= $length; $x++){

$split = explode(":", @$times[$x]);

 

A foreach() loop should be used for iterating over an array - not building a for() loop that would break if the array did not have sequential indexes starting at 0.

 

You state that your code above works for an array - but I don't see how that is possible. If the array has more than 1 "time" the current code is iterating over each item in the array and redefining the properties for hor, min & sec. THEN the code does the calculation. In other words the result of totaltime is completely based on the last element in the array. Any preceding values are not used in the calculation.

Link to comment
Share on other sites

Hey Dan,

 

I think this is a great example of where dependency injection offers a solution to a conundrum. I do have to note that your class has a significant issue. You apparently are trying to reduce the hours into days, but this is currently lossy, as you don't store days anywhere.

 

In this case, let's assume you have this code that works, so long as the data is in a particular format.

 

Now you have data where it doesn't match the format, so you now have a broken class that you are contemplating how to fix.

 

Personally, I'm with Barand 100% that DateTime objects are the way to go in PHP, but there are also cases where you may have tested code that is integrated with a system and can't be easily changed, or where the time/cost and potential breakage of changing things isn't feasible.

 

Now let's assume that your class was this instead of what it is now:

 

<?php
class times_counter {

    private $hou = 0;
    private $min = 0;
    private $sec = 0;
    private $totaltime = '00:00:00';

    public function __construct($times){
        $this->hou = (int)$times->getHours();
        $this->min = (int)$times->getMinutes();
        $this->sec = (int)$times->getSeconds();
        $this->totaltime = $this->hou . ":" . $this->min . ":" . $this->sec;    
    }

    public function get_total_time(){
        return $this->totaltime;
    }
}
Now it is no longer the job of your class to understand the internals of $times. And for $times to work all that is important is that it implements an interface that supports the methods getHours(), getMinutes(), and getSeconds(). Ostensibly, if other code that is working, is calling get_total_time() then you are not going to break your application so long as the format of get_total_time matches what is expected.

 

Just as an aside you might be able to see how a unit test on the class would be very valuable, that insured that the format of get_total_time() was guaranteed to a standard.

 

At any rate, PHP even helps you with this type of exercise by letting you declare an interface:

 

interface timeDataInterface {
    public function getHours();
    public function getMinutes();
    public function getSeconds();
}
Now to retrofit, you create classes that wrap any time data you need.

 

Class TimeDataArray implements timeDataInterface {
   public function __construct($times){
        private $hou;
        private $min;
        private $sec;
        
        if(is_array($times)){

            $length = sizeof($times);

            for($x=0; $x <= $length; $x++){
                    $split = explode(":", @$times[$x]); 
                    $this->hou += @$split[0];
                    $this->min += @$split[1];
                    $this->sec += @$split[2];
            }

            $seconds = $this->sec % 60;
            $minutes = $this->sec / 60;
            $minutes = (integer)$minutes;
            $minutes += $this->min;
            $hours = $minutes / 60;
            $minutes = $minutes % 60;
            $hours = (integer)$hours;
            $this->sec = $seconds;
            $this->min = $minutes;
            $this->hou = $hours;
        }
    }
    
    public function getHours() {
        return $this-hou;
    } 

    // Add getMinutes(), getSeconds()

}
Now your exercise in handling any other type of time data is simple: just insure you have a class that implements your interface, and you can pass that into your time_counter class with the expectation that things will work.

 

With PHP type hinting you can now add extra error checking, by insuring that any objects passed to your class actually implement the required timeDataInterface:

 

<?php
class times_counter {

    private $hou = 0;
    private $min = 0;
    private $sec = 0;
    private $totaltime = '00:00:00';

    public function __construct(timeDataInterface $times){
     ....
    }
   
Link to comment
Share on other sites

Hi folks,

 

Thanks for the replies. Really appreciate it.

Basically, I have the following (one for each day of the week), which gives a total hours worked each day, minus whatever period of time for breaks. It works fine and calculates the difference between the start time and end time and also subtracts the break period from the total.

                                       <?php
if(isset($_POST['start_shift7']) && $_POST['end_shift7'] && $_POST['break7'] != "") 
{
$datetime1 = new DateTime($_POST['start_shift7']);
$datetime2 = new DateTime($_POST['end_shift7']);

list($h, $m) = explode(":", $_POST['break7']);
$break = new DateInterval("PT{$h}H{$m}M");

$sundiff = $datetime1->add($break)->diff($datetime2);

?>
<input type="text" readonly class="form-control" name="sunday" value="<?php echo $sundiff->format('%H:%I'); ?>">
<?php
}
    ?>

Now, what I am trying to do, is get the totals from each day, add them together to get a total for the week.

 

I am not very well educated and the Jargon gets me 90% of the time. My apologies for that.

Link to comment
Share on other sites

For anyone interested, I got this working, with the help of a mate, with the following:

if(isset($_POST['calculate']) != ""){
class times_counter {

    private $hou = 0;
    private $min = 0;
    private $sec = 0;
    private $totaltime = '00:00:00';

    public function __construct($times){
        
        if(is_array($times)){

            $length = sizeof($times);

            for($x=0; $x <= $length; $x++){
                    $split = explode(":", @$times[$x]); 
                    $this->hou += @$split[0];
                    $this->min += @$split[1];
                    $this->sec += @$split[2];
            }

            $seconds = $this->sec % 60;
            $minutes = $this->sec / 60;
            $minutes = (integer)$minutes;
            $minutes += $this->min;
            $hours = $minutes / 60;
            $minutes = $minutes % 60;
            $hours = (integer)$hours;
            $hours += $this->hou % 24;
            $this->totaltime = $hours.":".$minutes.":".$seconds;
        }
    }

    public function get_total_time(){
        return $this->totaltime;
    }

}
$times = array(
   $mondiff->format('%H:%I'),
   $tudiff->format('%H:%I'),
   $weddiff->format('%H:%I'),
   $thdiff->format('%H:%I'),
   $fridiff->format('%H:%I'),
   $satdiff->format('%H:%I'),
   $sundiff->format('%H:%I'),
);
$counter = new times_counter($times);

echo $counter->get_total_time();
Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.