I have some total sums of hours and need to calculate the average. For example, my total hour value is 2452:43:44 (H:m:s) and the total count is 15. I would like to get the average time in the same format, that is hours:minutes:seconds. How can we do it in PHP ?
function average_time($total, $count, $rounding = 0) {
$total = explode(":", strval($total));
if (count($total) !== 3) return false;
$sum = $total[0]*60*60 + $total[1]*60 + $total[2];
$average = $sum/(float)$count;
$hours = floor($average/3600);
$minutes = floor(fmod($average,3600)/60);
$seconds = number_format(fmod(fmod($average,3600),60),(int)$rounding);
return $hours.":".$minutes.":".$seconds;
}
echo average_time("2452:43:44", 15); // prints "163:30:55"
echo average_time("2452:43:44", 15, 2); // prints "163:30:54.93"
Close to Antony's solution, but with array of hours given:
$time = array (
'2452:43:44',
'452:43:44',
'242:43:44',
'252:43:44',
'2:43:44'
);
$seconds = 0;
foreach($time as $hours) {
$exp = explode(':', strval($hours));
$seconds += $exp[0]*60*60 + $exp[1]*60 + $exp[2];
}
$average = $seconds/sizeof( $time );
echo floor($average/3600).':'.floor(($average%3600)/60).':'.($average%3600)%60;
$totalhourandmunite+=str_replace(":",'',$date);
strtoheur(round($totalhourandmunite/$nbdate,0));
function strtoheur($temp)
{
if(strlen($temp)==1) return $temp;
if(strlen($temp)==2)
$temp=$temp."00";
if(strlen($temp)==3)
$temp="0".$temp;
$temp=str_split($temp);
$heure=$temp["0"].$temp["1"];
$min=$temp["2"].$temp["3"];
if($min/60>1)
{
$min=$min%60;
$heure++;
}
if($min<10 && strlen($min)==1)
$min="0".$min;
if($heure>23)
{
$heure=$heure%24;
}
$temp=$heure.":".$min;
return $temp;
}
The best way would be to change the total hour value in seconds.
Divide it by total count value. What you will get is average in seconds.
Convert average back in H:m:s format.
Related
Have time slots which are in ascending order:
// 1st slot
$timeslot[] = '07:00-08:00';
// total = 1 hr
// 2nd slot
$timeslot[] = '07:15-07:30'; // not considered since it lies between the first slot ie 7 to 8
// total = 1 hr
// 3rd slot
$timeslot[] = '07:30-08:30'; // 1 hr of the first slot + remaining 30 minutes of this slot = 1:30 hrs
// total = 1:30 hrs
// 4rth slot
$timeslot[] = '10:45-11:45'; // 1:30 hrs + 1 hr
// total = 2:30 hrs
so far i have tried like this but no hope; what i'm trying to get is the time passed between the slots. for example we have two time slots 07:00-08:00 and 07:30-08:30, the time travelled in these two time slot is 1:30 hours. so something like this i'm calculating. My code goes like this:-
function addtimespend($dumparray = '', $i, $diff)
{
$arr1 = explode("-", $dumparray[0]);
if (isset($dumparray[$i])) {
$arr2 = explode("-", $dumparray[$i]);
if (strtotime($arr2[1]) > strtotime($arr1[1]) && strtotime($arr2[0]) < strtotime($arr1[1])) {
$diff = $diff + (strtotime($arr2[1]) - strtotime($arr1[1]));
return $diff;
} else {
$diff = $diff + (strtotime($arr1[1]) - strtotime($arr1[0]));
}
$i++;
return addtimespend($dumparray, $i, $diff);
} else {
$diff = $diff + (strtotime($arr1[1]) - strtotime($arr1[0]));
return $diff;
}
}
$flag = $diff = 0;
$diff = addtimespend($event, 1, 0);
function convertToHoursMins($time, $format = '%02d:%02d')
{
if ($time < 1) {
return;
}
$hours = floor($time / 60);
$minutes = ($time % 60);
return sprintf($format, $hours, $minutes);
}
echo convertToHoursMins($diff / 60, '%02d hours %02d minutes');
<?php
$timeslot = [];
$timeslot[] = '07:00-08:00';
$timeslot[] = '07:15-07:30';
$timeslot[] = '07:30-08:30';
$timeslot[] = '10:45-11:45';
$min_time = -1;
$max_time = -1;
$total_minutes = 0;
foreach($timeslot as $slot){
list($start_time,$end_time) = explode("-",$slot);
$start_time = explode(":",$start_time);
$start_time = intval($start_time[0]) * 60 + intval($start_time[1]); // converting to minutes
$end_time = explode(":",$end_time);
$end_time = intval($end_time[0]) * 60 + intval($end_time[1]);// converting to minutes
if($min_time == -1){// or max time for that matter (just basic initialization of these 2 variables)
$min_time = $start_time;
$max_time = $end_time;
$total_minutes += $max_time - $min_time;
}else{
if($start_time >= $max_time) $total_minutes += $end_time - $start_time;
else if($start_time < $max_time && $end_time > $max_time) $total_minutes += $end_time - $max_time;
$min_time = min($min_time,$start_time);
$max_time = max($max_time,$end_time);
}
}
echo intval($total_minutes / 60),":",($total_minutes % 60)," hrs";
Demo: https://3v4l.org/nvjDq
Algorithm:
Since your data is sorted according to start times, we can just keep track of min and max times of timeslots.
For simplicity, we can convert the timeslot in minutes.
We add to our total only under these 2 conditions:
If the current slot collides with the time range we maintain.
If the current slot is completely out of bounds of the current time range.
In the end, we print the answer in hours format.
i made a little script to calculate your timeslots, which works also fine with UNSORTED timeslots:
<?php
$timeslots = [];
// 2nd slot
$timeslots[] = '07:00-08:00'; // not considered since it lies between the first slot ie 7 to 8 // total = 1 hr
$timeslots[] = '07:15-08:00'; // 1st slot
$timeslots[] = '07:30-08:00'; // 1st slot
$timeslots[] = '07:30-08:30'; // 3rd slot
$timeslots[] = '07:45-08:45'; // 1 hr of the first slot + remaining 30 minutes of this slot = 1:30 hrs // total = 1:30 hrs // remove duplicate one's
// // 4rth slot
$timeslots[] = '10:45-11:45';
$test = new test;
foreach ($timeslots as $timeslot) {
$test->checkInBetween($timeslot);
}
$totalDiff = 0;
foreach ($test->sequences as $key => $sequence) {
$sequenceDifference = strtotime($sequence['latestEnd']) - strtotime($sequence['earliestStart']);
$totalDiff += $sequenceDifference;
}
echo "<pre>";
var_dump($totalDiff);
die();
class test {
public $sequences = [
0 => [
'earliestStart' => '',
'latestEnd' => '',
],
];
public function checkInBetween($timeslot) {
$exploded = explode('-', $timeslot);
$isEarliest = false;
$isLatest = false;
$isBetweenFirst = false;
$isBetweenSecond = false;
$sequenceFound = false;
foreach ($this->sequences as $key => $sequence) {
// Check if the first number is the earliest
if (($exploded[0] < $sequence['earliestStart'])) {
$isEarliest = true;
}
// Check if the last number is the latest
if (($exploded[1] > $sequence['latestEnd'])) {
$isLatest = true;
}
if ($exploded[0] > $sequence['earliestStart'] && $exploded[0] < $sequence['latestEnd']) {
$isEarliest = false;
$isBetweenFirst = true;
}
if ($exploded[1] > $sequence['earliestStart'] && $exploded[1] < $sequence['latestEnd']) {
$isLatest = false;
$isBetweenSecond = true;
}
if (($isEarliest && $isLatest) || ($isEarliest && $isBetweenSecond)) {
$this->sequences[$key]['earliestStart'] = $exploded[0];
$sequenceFound = true;
}
if (($isEarliest && $isLatest) || ($isLatest && $isBetweenFirst)) {
$this->sequences[$key]['latestEnd'] = $exploded[1];
$sequenceFound = true;
}
}
if (!$sequenceFound) {
$this->sequences[] = [
'earliestStart' => $exploded[0],
'latestEnd' => $exploded[1],
];
}
}
}
Feel free to ask questions. Please mind that the output (totalDiff) contains seconds!
A few words to the script:
The script checks every value inside the timeslots array and tries to merge it into a sequence if the starting time is in between an existing sequence or the ending time is in between an existing sequence. If one of those conditions are met, the sequence is updated with the new value.
If none of those conditions are met, the script adds a new sequence, as the current values are not matching any existing conditions.
After iterating every value inside the timeslot, the sequences will be calculated in terms of difference in seconds, which will be added to the totalDiff.
This code will work if the time slots are shorted by their start time in ascending order.
<?php
$timeslots[] = '07:00-08:00';
$timeslots[] = '07:15-07:30';
$timeslots[] = '07:30-08:30';
$timeslots[] = '10:45-11:45';
$slots=array();
foreach($timeslots as $timeslot){
$timeslot=explode("-",$timeslot);
$start=toMinutes($timeslot[0]);
$end=toMinutes($timeslot[1]);
$slots[]=["start"=>$start,"end"=>$end];
$starts[]=$start;
$ends[]=$end;
}
function toMinutes($time){
$arr= explode(":",$time);
return ($arr[0] * 60) + $arr[1];
}
function toTime($minutes){
return floor($minutes / 60) .":". $minutes % 60;
}
function totalGapMinutes($slots){
$count=count($slots);
$i=0;
$gap=0;
for($i; $i<$count-1; $i++){
if($slots[$i]['end']<$slots[$i+1]['start']){
$gap+=$slots[$i+1]['start']-$slots[$i]['end'];
}
}
return $gap;
}
var_dump(toTime(max($ends)-min($starts) - totalGapMinutes($slots)));
I have a script to count the time a ticket is open each day, but only for hours we are open. The details of the functions arent that important but i have pasted it all here as it may be the cause for the failure.
Heres the function:
function getTime($o, $now, $total) {
//One Day in seconds
$oneDay = 86400;
//One Business day (12 hours, 7am-7pm)
$oneBDay = 43200;
//Get the timestamp of 7am/7pm for time given
$sevenAM = mktime('7', '0', '0', m($o), d($o), y($o));
$sevenPM = mktime('19', '0', '0', m($o), d($o), y($o));
//If Ticket Start Time is before 7am, we only count from 7am after
if ($o < $sevenAM) {
$o = $sevenAM;
} else {
$o = $o;
}
//Debug to get today
$today = date('Y-m-d h:i:s a', $o);
//See if we are within the same business day
$diff = $now - $o;
//Debug
//echo $today.",".$timeSpent.",".$total."\n";
//If we are not within 1 business day, do this again
if ($diff > $oneBDay) {
//Total Time spent for the day
$timeSpent = $sevenPM - $o;
//Add todays time to total time
$total = $total + $timeSpent;
//Move to tomorrow
$o = $sevenAM + $oneDay;
getTime($o, $now, $total);
}
//If we are within 1 business day, count the time for today and return our result
if ($diff < $oneBDay) {
$time = $diff;
$total = $total + $time; //for example $total = 123456
return $total;
}
}
when I do
echo getTime($o,$now,0);
I would expect to see 123456. But i get nothing printed.
The function runs and I know total has a value ( I have set it statically as a debug).
--Note the function calls itself if needed
additional functions:
function y($o){
$y = date('Y',$o);
return $y;
}
function m($o){
$m = date('m',$o);
return $m;
}
function d($o){
$d = date('d',$o);
return $d;
}
EDIT:
if i do :
if ($diff < $oneBDay) {
$time = $diff;
$total = $total + $time; //for example $total = 123456
echo "My Total:".$total;
return $total;
}
I will see My Total:123456
It's not in vain to point out that your function is hard to debug due to structural flaws. I suggest you to create a Unit Test for your function and then refactor so you will be able to make sure that you preserve the desired behaviour.
That said, your function is printing anything because it's not reaching any explicit return directive. So it returns null. See that if the last if is not hit, you will miss the last chance for returning a value.
I'm not sure what your function should do, but it looks like if you call it recursively, you may want to return it's value, or at least reassign to a variable. Checkout for that.
<?php
function y($o){ $y = date('Y',$o); return $y; }
function m($o){ $m = date('m',$o); return $m; }
function d($o){ $d = date('d',$o); return $d; }
function getTime($o,$now,$total){
//One Day in seconds
$oneDay = 86400;
//One Business day (12 hours, 7am-7pm)
$oneBDay = 43200;
//Get the timestamp of 7am/7pm for time given
$sevenAM = mktime('7','0','0',m($o),d($o),y($o));
$sevenPM = mktime('19','0','0',m($o),d($o),y($o));
//If Ticket Start Time is before 7am, we only count from 7am after
if ($o < $sevenAM){
$o = $sevenAM;
}else{
$o = $o;
}
//Debug to get today
$today = date('Y-m-d h:i:s a',$o);
//See if we are within the same business day
$diff = $now - $o;
//Debug
//echo $today.",".$timeSpent.",".$total."\n";
//If we are not within 1 business day, do this again
if ($diff > $oneBDay){
//Total Time spent for the day
$timeSpent = $sevenPM - $o;
//Add todays time to total time
$total = $total+$timeSpent;
//Move to tomorrow
$o = $sevenAM+$oneDay;
return getTime($o,$now,$total); // LOOKS LIKE YOU WANT TO RETURN VALUE HERE
}
//If we are within 1 business day, count the time for today and return our result
if($diff < $oneBDay){
$time = $diff;
$total = $total+$time; // FIXED MISSING SEMICOLON HERE TO AVOID SYNTAX ERROR
return $total;
}
}
$test = getTime(1534964212, date('U'), 0);
echo "$test"; // 144885
?>
Although I'm not exactly sure what you tried to do with this function, I've corrected a few syntax errors, and added some returns for cases that were missing. (inside if ($diff > $oneBDay) { and changed if ($diff < $oneBDay) { to if ($diff <= $oneBDay) {)
<?php
function getTime($o, $now, $total) {
//One Day in seconds
$oneDay = 86400;
//One Business day (12 hours, 7am-7pm)
$oneBDay = 43200;
//Get the timestamp of 7am/7pm for time given
$sevenAM = mktime('7', '0', '0', m($o), d($o), y($o));
$sevenPM = mktime('19', '0', '0', m($o), d($o), y($o));
//If Ticket Start Time is before 7am, we only count from 7am after
if ($o < $sevenAM) {
$o = $sevenAM;
}
//See if we are within the same business day
$diff = $now - $o;
//If we are not within 1 business day, do this again
if ($diff > $oneBDay) {
//Total Time spent for the day
$timeSpent = $sevenPM - $o;
//Add todays time to total time
$total = $total + $timeSpent;
//Move to tomorrow
$o = $sevenAM + $oneDay;
return getTime($o, $now, $total);
}
//If we are within 1 business day, count the time for today and return our result
if ($diff <= $oneBDay) {
$time = $diff;
$total = $total + $time; //for example $total = 123456;
return $total;
}
}
function y($o){ $y = date('Y',$o); return $y; }
function m($o){ $y = date('m',$o); return $y; }
function d($o){ $y = date('d',$o); return $y; }
$o = 1534964212;
$now = date('U');
echo getTime($o,$now,0);
now it returns something like 145111
I want to get the difference in two times that are in hh:mm format. I am using this function
<?php
function timeDiff($firstTime,$lastTime) {
$firstTime=strtotime($firstTime);
$lastTime=strtotime($lastTime);
$timeDiff=$lastTime-$firstTime;
return $timeDiff;
}
echo (timeDiff("10:00","20:00")/60)/60;
?>
The issue is that it works perfectly if I have hours less than 24. But I need it to work for upto 60 hours. Like 60:00 - 02:25 should give me 57:35 and 60:00 - 00:00 should give me 60:00. Where are I doing wrong?
If you only work with hours + minutes, then you can just calculate the timestamp yourself, something like that:
function calculateSeconds($time) {
$timeParts = explode(':', $time);
return (int)$timeParts[0] * 3600 + (int)$timeParts[1] * 60;
}
and then use it in your function
function timeDiff($firstTime, $lastTime) {
return calculateSeconds($lastTime) - calculateSeconds($firstTime);
}
You can use gmdate() function as bellow.
function timeDiff($firstTime,$lastTime) {
$a_split = explode(":", $firstTime);
$b_split = explode(":", $lastTime);
$a_stamp = mktime($a_split[0], $a_split[1]);
$b_stamp = mktime($b_split[0], $b_split[1]);
if($a_stamp > $b_stamp)
{
$diff = $a_stamp - $b_stamp; //69600
}else{
$diff = $b_stamp - $a_stamp; //69600
}
$min = gmdate("i", $diff);
$d_hours = gmdate("d", $diff)==1 ? 0 : gmdate("d", $diff)*12 ;
$hours = $d_hours + gmdate("H", $diff) ;
echo $hours . ':' . $min; // 56:12:12
}
timeDiff("35:05", "01:45");
I would like to know how to subtract two variables that represent minutes in PHP
For example I have two minute variables
$minutes1 = 20;
$minutes2 = 45;
$totalMinutes = $minutes1 -$minutes2;
//output should be 35 as $totalMinutes
An example would be
$time1 = "2:20";
$time2 = "3:45";
$finalTime = $time2 - $time1
//final time = 1:25
I am only interested in the minutes and not the hours
I bet that there's some cleaner way, but this seem to do what you're asking for.
$m1 = 20;
$m2 = 45;
$diff = $m1 - $m2;
echo $diff >= 0 ? $diff : $diff + 60;
This returns 35. Demo: https://3v4l.org/WaC8r
EDIT: Based on comments I have a better understanding of what you are asking for and have written this function.
function subtractMinutes($start, $sub) {
$res = $start;
while ($sub > 0) {
if ($sub >= 60) {
$sub -= 60;
continue;
}
if ($res >= $sub) {
$res -= $sub;
break;
}
if ($sub > $res) {
$sub -= $res + 1;
$res = 59;
continue;
}
$sub -= $res;
$res = 0;
}
return $res;
}
var_dump(subtractMinutes(20, 45)); //35
var_dump(subtractMinutes(20, 60)); //20
var_dump(subtractMinutes(20, 120)); //20
var_dump(subtractMinutes(20, 121)); //19
var_dump(subtractMinutes(40, 40)); //0
var_dump(subtractMinutes(59, 58)); //1
Please note that this answer attempts to provide a general solution.
If you only need to subtract a couple of times by all means, just
check with 60.
I would insist on suggesting you should be using decimals for all operations, and only turn into the correct format when outputting the result on a page. I believe it is safer to do calculations this way, instead of relying on you remembering to add/subtract 60 every time.
Examples:
$single_minute = 1.66;
$twenty_minutes = 20*1.66 = 33.2;
$sixty_minutes = 60*1.66 = 99.6;
When outputing:
$out_twenty = round(33.2/1.66);
$out_sixty = round(99.6/1.66);
You can use helper constants:
define("MINUTE", 1.66);
//You want to calculate 34 minutes
$thirtyfour_minutes = MINUTE * 34;
//You want to output 34 minutes
echo round($thirtyfour_minutes);
I have a list of video segment durations I need to add up to get the total duration.
The series is like this:
0:33
4:30
6:03
2:10
...etc
I need to add up the minutes and seconds to get a total video duration.
Here's the modified function of my accepted answer:
function getTotalDuration ($durations) {
$total = 0;
foreach ($durations as $duration) {
$duration = explode(':',$duration);
$total += $duration[0] * 60;
$total += $duration[1];
}
$mins = floor($total / 60);
$secs = str_pad ( $total % 60, '2', '0', STR_PAD_LEFT);
return $mins.':'.$secs;
}
Just made sure the output looks correct.
Give this code a shot:
function getTotalDuration ($durations) {
$total = 0;
foreach ($durations as $duration) {
$duration = explode(':',$duration);
$total += $duration[0] * 60;
$total += $duration[1];
}
$mins = $total / 60;
$secs = $total % 60;
return $mins.':'.$secs;
}
This stores the result in $seconds:
$seconds = 0;
foreach ($times as $time):
list($m,$s) = explode(':',$time);
$seconds += $s + 60*$m;
endforeach;
Convert all times to seconds, add them as integers, convert the sum back to minutes and seconds?