coolbeansdude51 Posted March 7, 2009 Share Posted March 7, 2009 Hello forum, I am trying to figure out how to do the average time in an array full of time which is formatted like below: 20:49:44 19:50:36 03:14:15 21:45:40 21:34:11 04:07:53 etc. How can I figure out the average time of all of those times? I was thinking we would have to break apart each section of the time. So break apart the hours. Average that. Break apart the minutes. Average that. Break apart the seconds. Average that. I am assuming the explode function would do the best for this. Take the ':' out of the string. Will that give me an accurate average? <? $time1 = explode(':', $string); $hour = average($time1[0]); $minute = average($time1[1]); $second = average($time1[2]); //array average( array input ) function average($input) { return array_sum($input) / count($input); } ?> I thought that would work ... but it didn't. It gave me an error of "Warning: array_sum() [function.array-sum]: The argument should be an array in filelocation" Any ideas? Thanks in advance! Quote Link to comment Share on other sites More sharing options...
coolbeansdude51 Posted March 7, 2009 Author Share Posted March 7, 2009 Ok now ... I am thinking it should be more like this. $i = 0; while ($i <= 99) { $test = explode(' ',$friends->status[$i]->created_at); $test1 = explode(':', $test[3]); $i++; }; $hour = average($test1[0]); $minute = average($test1[1]); $second = average($test1[2]); echo $minute; //array average( array input ) function average($input) { return array_sum($input) / count($input); } But that doesn't work either. Keeps telling me that the test1 var is not an array ... I am making it an array in the while statement? Anyone got any idea's? Quote Link to comment Share on other sites More sharing options...
coolbeansdude51 Posted March 7, 2009 Author Share Posted March 7, 2009 Ok. After a ton of trial and error I figure this out ... <? $i = 0; $stop = count($friends->status->created_at); while ($i <= $stop) { $test = explode(' ',$friends->status[$i]->created_at); $bigtime[$i] = $test[3]; $smaller[$i] = explode(':', $bigtime[$i]); $hour[$i] = $smaller[$i][0]; $minute[$i] = $smaller[$i][1]; $second[$i] = $smaller[$i][2]; $i++; }; $aveghour = round(average($hour)); $avegminute = round(average($minute)); $avegsecond = round(average($second)); //array average( array input ) function average($input) { return array_sum($input) / count($input); } echo $aveghour.":".$avegminute.":".$avegsecond; ?> Works for me! Hope it helps someone else. Still wondering if it gives you an accurate average for time. Any thoughts? Quote Link to comment Share on other sites More sharing options...
Psycho Posted March 7, 2009 Share Posted March 7, 2009 I'm not sure how your 'array' is constructed, but when I tested your code it created an empty element at the end of each record - skewing the results (because of the <= in the while loop). Even after I corrected for that, the code still calculates incorrectly. Using the times 1:10:00 & 1:05:00 & 2:55:00 it calculated the average as 1:23:0. But, if you convert the times to minutes you get: (70 + 65 + 175) = 310 / 3 = 103 minutes averaged. 103 minutes is 1:43:00. Give me a sec and I'll give you some code that works Quote Link to comment Share on other sites More sharing options...
Psycho Posted March 7, 2009 Share Posted March 7, 2009 <?php function averageTime($timesArr) { foreach($timesArr as $timeStr) { //Convert to seconds and add to array $seconds[] = hms2sec($timeStr); } return sec2hms(round(array_average($seconds))); } function hms2sec($time) { //Split time into parts $timeParts = explode(':', $time); return ($timeParts[0]*3600 + $timeParts[1]*60 + $timeParts[2]); } function sec2hms($seconds) { $hours = number_format(intval($seconds/3600), 0); $minutes = str_pad(intval($seconds%3600/60),2, '0', STR_PAD_LEFT); $seconds = str_pad($seconds%60,2, '0', STR_PAD_LEFT); return "$hours:$minutes:$seconds"; } function array_average($array) { return (array_sum($array)/count($array)); } $times = array('1:10:00', '1:05:00', '2:55:00'); echo averageTime($times); ?> Will output 1:43:20 (which is correct). Quote Link to comment Share on other sites More sharing options...
coolbeansdude51 Posted March 7, 2009 Author Share Posted March 7, 2009 Looks good. When I pump in my numbers (about 800 - 10,000) of them. I get this: 339:18:25 I then tired a different string (800 - 10,000) of them and got 342:48:1720. This is 24hour time UTC. I am guessing the hour's section is off and maybe even the seconds section. Any suggestions? Quote Link to comment Share on other sites More sharing options...
coolbeansdude51 Posted March 7, 2009 Author Share Posted March 7, 2009 Also. I had to include the while statement to make it work. $friends->status[$i]->created_at section is a massive array of XML data. The created at part is all I want. To separate it out I use the explode method. Because the array looks like this: [98] => Array ( [0] => Fri [1] => Mar [2] => 06 [3] => 18:28:22 [4] => +0000 [5] => 2009 ) That is why the function must process only the 3 section of the array cause that is the part that has all the times in it. Any other help or advise? $i = 0; $stop = count($friends->status); while ($i <= $stop) { $times[] = explode(' ',$friends->status[$i]->created_at); $i++; }; function averageTime($timesArr) { foreach($timesArr as $timeStr) { //Convert to seconds and add to array $seconds[] = hms2sec($timeStr); } return sec2hms(round(array_average($seconds))); } function hms2sec($time) { //Split time into parts $timeParts = explode(':', $time); return ($timeParts[0]*3600 + $timeParts[1]*60 + $timeParts[2]); } function sec2hms($seconds) { $hours = number_format(intval($seconds/3600), 0); $minutes = str_pad(intval($seconds%3600/60),2, '0', STR_PAD_LEFT); $seconds = str_pad($seconds%60,2, '0', STR_PAD_LEFT); return "$hours:$minutes:$seconds"; } function array_average($array) { return (array_sum($array)/count($array)); } echo averageTime($times[3]); Quote Link to comment Share on other sites More sharing options...
Psycho Posted March 8, 2009 Share Posted March 8, 2009 Hmm.. Those are some odd results. But, looking at the code you posted I'm seeing some errors and odd logic. First off, there is the error I alluded to earlier $i = 0; $stop = count($friends->status); while ($i <= $stop) { If there are 10 records and the first record is at index 0, then our loop should continue until index number 9 (0-9 is 10 elements). So the while loop should be "($i < $stop)" not "($i <= $stop)" which will go from 0 to 10, i.e. 11 elements. Next you have this code $times[] = explode(' ',$friends->status[$i]->created_at); You state that $friends->status[$i]->created_at is an array, but you use explode on it? Even if we assume it is a string that you then convert to an array, you are then assigning that array to $times[], but then you only process $times[3]. I *think* what you want to be processing is $times[n][3], where n represents each record. Give this a try <?php $i = 0; $record_count = count($friends->status) while ($i < $record_count) { $record = explode(' ', $friends->status[$i]->created_at); $thisTime = $record[3]; if (!echo preg_match('/^\d{1,2}:\d{1,2}:\d{1,2}$/', $thisTime) { echo "Invalid time: [$thisTime], record $i<br>"; } else { $times[] = $thisTime; } $i++; } function averageTime($timesArr) { foreach($timesArr as $timeStr) { //Convert to seconds and add to array $seconds[] = hms2sec($timeStr); } return sec2hms(round(array_average($seconds))); } function hms2sec($time) { //Split time into parts $timeParts = explode(':', $time); $seconds = ($timeParts[0]*3600 + $timeParts[1]*60 + $timeParts[2]); //echo "hms2sec: Input ($time), Output ($seconds}<br>"; return $seconds; } function sec2hms($seconds) { $hours = intval($seconds/3600); $minutes = intval($seconds%3600/60); $seconds = ($seconds%60); $hms = sprintf("%s:%02s:%02s", $hours, $minutes, $seconds); echo "sec2hms: Input ($seconds), Output ($hms}<br>"; return $hms; } function array_average($array) { return (array_sum($array)/count($array)); } echo averageTime($times); ?> For further debugging, hard code the value of $record_count to be something like 10 and then uncomment the other debuggin line in the hms2sec() function. I wouldn't have that line uncommented if you are running thousands of records. Quote Link to comment Share on other sites More sharing options...
coolbeansdude51 Posted March 8, 2009 Author Share Posted March 8, 2009 Looks like that worked! You missed a couple of ('s and ;'s so I edited the code! This is what it should look like. Also I am assuming that the "if(!echo preg_match" was an error and should be "if(!preg_match". Am I correct in that? $i = 0; $record_count = count($friends->status); while($i < $record_count) { $record = explode(' ', $friends->status[$i]->created_at); $thisTime = $record[3]; if(!preg_match('/^\d{1,2}:\d{1,2}:\d{1,2}$/', $thisTime)){ echo "Invalid time: [$thisTime], record $i<br>"; } else { $times[] = $thisTime; } $i++; } function averageTime($timesArr) { foreach($timesArr as $timeStr) { //Convert to seconds and add to array $seconds[] = hms2sec($timeStr); } return sec2hms(round(array_average($seconds))); } function hms2sec($time) { //Split time into parts $timeParts = explode(':', $time); $seconds = ($timeParts[0]*3600 + $timeParts[1]*60 + $timeParts[2]); //echo "hms2sec: Input ($time), Output ($seconds}<br>"; return $seconds; } function sec2hms($seconds) { $hours = intval($seconds/3600); $minutes = intval($seconds%3600/60); $seconds = ($seconds%60); $hms = sprintf("%s:%02s:%02s", $hours, $minutes, $seconds); echo "sec2hms: Input ($seconds), Output ($hms}<br>"; return $hms; } function array_average($array) { return (array_sum($array)/count($array)); } echo averageTime($times); Thanks so much for your help! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.