Difference between durations - php

I am creating a timesheet whereby it shows expected and actual hours.
The durations are saved like the below
23:15 - 23 hours and 15 mins
25:45 - 25 hours and 45 mins
I need to work out the difference in hours and mins between the two (extra hours worked)
I have tried the below
$acutal=='23:15';
$expected=='25:45';
$start_time = new DateTime("1970-01-01 $acutal:00");
$time = $start_date->diff(new DateTime("1970-01-01 $expected:00"));
This does work, however when the hours are over 24:00 it throws an error (obviously because it's reading it as time)
Uncaught exception 'Exception' with message 'DateTime::__construct():
Failed to parse time string (1970-01-01 25:45:00)
Is there another way to do this?

You could check if the number of hours are greater than 24, and if so, add a day, and remove 24 hours.
$actual='23:15';
$expected='25:45';
$day = 1;
list($hrs, $min) = explode(':', $expected);
if ($hrs > 24) { $day += 1; $hrs -= 24; }
$start_time = new DateTime("1970-01-01 $actual:00");
$time = $start_time->diff(new DateTime("1970-01-$day $hrs:$min:00"));
echo $time->format('%hh %Im');
Output:
2h 30m
Please also note that == is used to compare, not to assign.
You can also change the if ($hrs > 24) by while(), if there is 48 hours or more.
edit
As pointed out by #CollinD, if the time exceed the number of days of the month, it will fail. Here is another solution:
$actual='23:15';
$expected='25:45';
list($hrs, $min) = explode(':', $actual);
$total1 = $min + $hrs * 60;
list($hrs, $min) = explode(':', $expected);
$diff = $min + $hrs * 60 - $total1;
$start_time = new DateTime();
$expected_time = new DateTime();
$expected_time->modify("+ $diff minutes");
$time = $start_time->diff($expected_time);
echo $time->format('%hh %Im');

You can do it manually by keeping track of the number of minutes worked - this will be exact and will also allow you to show negative differences.
<?php
// get the difference in H:mm between two H:mm
function diff_time($actual, $expected) {
$diff_mins = mins($actual) - mins($expected);
return format_mins($diff_mins);
}
// convert a HH:mm to number of minutes
function mins($t) {
$parts = explode(':', $t);
return $parts[0] * 60 + $parts[1];
}
// convert number of minutes into HH:mm
function format_mins($m) {
$mins = $m % 60;
$hours = ($m - $mins) / 60;
// format HH:mm
return $hours . ':' . sprintf('%02d', abs($mins));
}
var_dump(diff_time('23:15', '25:45'));
var_dump(diff_time('25:15', '23:45'));
This outputs:
string(5) "-2:30"
string(4) "1:30"
.. first, 2:30 less than expected, for the second 1:30 more than expected.

You can try using datetime functions but it seems a lot more straightforward to me to treat the times as string, use split or explode to get hours and minutes, convert to integers, get the difference in minutes and convert it back to hours and minutes (integer divide by 60 and remainder).
$t1=explode(':',$expected);
$t2=explode(':',$actual);
$d=60*($t1[0]-$t2[0])+t1[1]-t2[1];
$result=str_pad(floor($d/60),2,'0',STR_PAD_LEFT).':'.str_pad($d%60,2,'0',STR_PAD_LEFT);

Related

Calculate Total time from array in php if total time greater than 24 hours

I want to get the sum of the time in array. There are a lot of questions asked before related this question. Only problem this solution work the only sum is less than 24 hours. After 24 hours it will start at 00:00:00. How do I get more than 24 hours as total?
<?php
$total = [
'00:02:55',
'00:07:56',
'01:03:32',
'15:13:34',
'02:13:44',
'03:08:53',
'13:13:54'
];
$sum = strtotime('00:00:00');
$sum2=0;
foreach ($total as $v){
$sum1=strtotime($v)-$sum;
$sum2 = $sum2+$sum1;
}
$sum3=$sum+$sum2;
echo date("H:i:s",$sum3);
?>
RESULT
11:04:28
Expected result
35:04:28
DEMO LINK
Try the following code
<?php
function explode_time($time) { //explode time and convert into seconds
$time = explode(':', $time);
$time = $time[0] * 3600 + $time[1] * 60;
return $time;
}
function second_to_hhmm($time) { //convert seconds to hh:mm
$hour = floor($time / 3600);
$minute = strval(floor(($time % 3600) / 60));
if ($minute == 0) {
$minute = "00";
} else {
$minute = $minute;
}
$time = $hour . ":" . $minute;
return $time;
}
$time = 0;
$time_arr = [
'00:02:55',
'00:07:56',
'01:03:32',
'15:13:34',
'02:13:44',
'03:08:53',
'13:13:54'
];
foreach ($time_arr as $time_val) {
$time +=explode_time($time_val); // this fucntion will convert all hh:mm to seconds
}
echo second_to_hhmm($time);
?>
With the external DateTime Extension dt you can add all times to a date.
With DateTime::diff you get the result:
$dt = dt::create("2000-1-1"); //fix Date
$dtsum = clone $dt;
foreach($total as $time){
$dtsum->addTime($time);
}
$diff = $dt->diff($dtsum);
printf('%d:%02d:%02d',$diff->days * 24 + $diff->h,$diff->i,$diff->s);
Output:
35:04:28
Update
Without a DateTime-Extension:
$dt = date_create("2000-1-1"); //fix Date
$dtsum = clone $dt;
foreach($total as $time){
$timeArr = explode(":",$time);
$secondsAdd = $timeArr[0] * 3600 + $timeArr[1] * 60 +$timeArr[2];
$dtsum->modify($secondsAdd." Seconds");
}
$diff = $dt->diff($dtsum);
printf('%d:%02d:%02d',$diff->days * 24 + $diff->h,$diff->i,$diff->s);
Look at what you are doing: using time to make computations ignoring date part.
Maybe considering things in another way : 1 hour = 60 seconds * 60 minutes. So convert all you iterations as seconds, do the sum at the end and write time you need yourself.
Or, or you will use some greater things from php documentation
<?php
$january = new DateTime('2010-01-01');
$february = new DateTime('2010-02-01');
$interval = $february->diff($january);
// %a will output the total number of days.
echo $interval->format('%a total days')."\n";
// While %d will only output the number of days not already covered by the
// month.
echo $interval->format('%m month, %d days');
Adapt to your needs, and I am sure it will work well.
Personally I would completely avoid touching any date functions because you're not working with dates. You could do something like:
// Input data
$data = [
'00:02:55',
'00:07:56',
'01:03:32',
'15:13:34',
'02:13:44',
'03:08:53',
'13:13:54'
];
// Total to hold the amount of seconds
$total = 0;
// Loop the data items
foreach($data as $item):
$temp = explode(":", $item); // Explode by the seperator :
$total+= (int) $temp[0] * 3600; // Convert the hours to seconds and add to our total
$total+= (int) $temp[1] * 60; // Convert the minutes to seconds and add to our total
$total+= (int) $temp[2]; // Add the seconds to our total
endforeach;
// Format the seconds back into HH:MM:SS
$formatted = sprintf('%02d:%02d:%02d', ($total / 3600),($total / 60 % 60), $total % 60);
echo $formatted; // Outputs 35:04:28
So we loop the items in the input array and explode the string by the : to get an array containing hours, minutes and seconds in indexes 0, 1, and 2.
We then convert each of those values to seconds and add to our total. Once we're done, we format back into HH:MM:SS format

PHP - How to deduct a time to a total time without converting to decimal?

I'm currently working with a timekeeping system which computes the sum of the basic hours of the week and deduct certain time if there's a late record.
Given that the employee has a total hours rendered for this week is 45 hours (45:00), and he she/has a total late record for that week of 50 minutes (00:50),
Using, PHP. How can I deduct the late record to the total hours rendered without converting time to decimal? The desired output for the above sample is 44:10 since 00:50 is deducted to 45:00.
I see so your goal is to subtract durations ex.
45:00 - 00:50 = 44:10
1: Create a function that convert them into hours
function convertToHours($duration) {
$duration = explode(':',$duration);
$hours+= (int)$duration[0];
$hours+= (int)$duration[1] / 60;
return $hours;
}
2: Create a funciton thats convert from seconds to duration hours:seconds
function secondsToDuration($seconds) {
$H = floor($seconds / 3600);
$i = ($seconds / 60) % 60;
$s = $seconds % 60;
return sprintf("%02d:%02d:%02d", $H, $i, $s);
}
Convert them into hours using function created
$duration1 = convertToHours("25:00");
$duration2 = convertToHours("00:50");
Then subtract them
$difference = $duration1 - $duration2;
Lastly use the created method which convert them back into duration
$duration = secondsToDuration($difference * 3600);
See Demo here
Hope it helps you
You can convert the string to a date and get the difference.
$d1 = "00:45:00";
$d2 = "00:00:50";
date_default_timezone_set("utc");
$fakedate = '01/01/2017';
$d1 = $fakedate . ' ' . $d1;
$d2 = $fakedate . ' ' . $d2;
$dt1 = new DateTime($d1);
$dt2 = new DateTime($d2);
$diff = $dt1->diff($dt2);
echo $diff->format("%H:%I:%S");
The output will be: 00:44:10

Formating integers in percentage in php

I have two integers that are $hours = 74 and $minutes = 20, the format I need to get them in is following: hours and minutes (without any spacing) in percentage of one hour. So in this case the final result should be 7433.
Just to make it more clear if the two numbers would be $hours = 74 and $minutes = 30, the final result should be 7450.
I have been trying to look for similar functions, but without any success.
Any help or guidance is much appreciated.
So really what you are looking for is $result = $hours . floor($minutes/60*100); ?
Or if you need the leading zeroes: $result = str_pad($hours,2,'0') . str_pad(floor($minutes/60*100),2,'0');
Save yourself the pain of coming up with code that handles cases where the value of $minutes >= 60 by using the DateTimeInterface objects. I admit, they may seem overkill in this situation, but they are very sturdy and reliable. Plus, if ever you'd want to add days, weeks, months, years or seconds to this code, the DateTimeInterface classes are already equipped for the job:
$now = new DateTime();
$comp = clone $now;
//2 identical datetime instances
//add hours + minutes to either one
$comp->add(
sprintf(
'PT%dH%dM',
$hours,
$minuts
)
);
//get difference in seconds
$diff = $comp->getTimeStamp() - $now->getTimeStamp();
//or echo, I used printf to limit the number of decimals to 2
printf(
'%.2f hours difference'
$diff/3600 //1 hour === 3600 seconds
);
Just browse the DateTime docs, and other classes/interfaces like DateInterval and others implementing the DateTimeInterface.
Just for completeness, here's how I'd set about doing this "manually"
$decimalT = $hours + floor($minutes/60) + ($minutes%60)/60
//add hours in case $minutes>= 60
//floor($minutes/60);
//get remainder minutes, converted to decimal hours
//($minutes%60)/60;
printf(
'%d hours + %d seconds == %.2f hours',
$hours,
$minutes,
$decimalT
);
Use this snippet of code:
$hours = 74;
$minutes = 20;
$totalMinutes = $hours * 60 + $minutes;
$percentage = floor(($totalMinutes * 100) / 60);
var_dump($percentage);

Convert dates to hours

I'm trying to work with dates for the first time, I did it something about that with Flash but it's different.
I have two different dates and I'd like to see the difference in hours and days with them, I've found too many examples but not what I'm loking for:
<?php
$now_date = strtotime (date ('Y-m-d H:i:s')); // the current date
$key_date = strtotime (date ("2009-11-21 14:08:42"));
print date ($now_date - $key_date);
// it returns an integer like 5813, 5814, 5815, etc... (I presume they are seconds)
?>
How can I convert it to hours or to days?
The DateTime diff function returns a DateInterval object. This object consists of variabeles related to the difference. You can query the days, hours, minutes, seconds just like in the example above.
Example:
<?php
$dateObject = new DateTime(); // No arguments means 'now'
$otherDateObject = new DateTime('2008-08-14 03:14:15');
$diffObject = $dateObject->diff($otherDateObject));
echo "Days of difference: ". $diffObject->days;
?>
See the manual about DateTime.
Sadly, it's a PHP 5.3> only feature.
Well, you can always use date_diff, but that is only for PHP 5.3.0+
The alternative would be math.
How can I convert it [seconds] to hours or to days?
There are 60 seconds per minute, which means there are 3600 seconds per hour.
$hours = $seconds/3600;
And, of course, if you need days ...
$days = $hours/24;
If you dont have PHP5.3 you could use this method from userland (taken from WebDeveloper.com)
function date_time_diff($start, $end, $date_only = true) // $start and $end as timestamps
{
if ($start < $end) {
list($end, $start) = array($start, $end);
}
$result = array('years' => 0, 'months' => 0, 'days' => 0);
if (!$date_only) {
$result = array_merge($result, array('hours' => 0, 'minutes' => 0, 'seconds' => 0));
}
foreach ($result as $period => $value) {
while (($start = strtotime('-1 ' . $period, $start)) >= $end) {
$result[$period]++;
}
$start = strtotime('+1 ' . $period, $start);
}
return $result;
}
$date_1 = strtotime('2005-07-31');
$date_2 = time();
$diff = date_time_diff($date_1, $date_2);
foreach ($diff as $key => $val) {
echo $val . ' ' . $key . ' ';
}
// Displays:
// 3 years 4 months 11 days
TheGrandWazoo mentioned a method for php 5.3>. For lower versions you can devide the number of seconds between the two dates with the number of seconds in a day to find the number of days.
For days, you do:
$days = floor(($now_date - $key_date) / (60 * 60 * 24))
If you want to know how many hours are still left, you can use the modulo operator (%)
$hours = floor((($now_date - $key_date) % * (60 * 60 * 24)) / 60 * 60)
<?php
$now_date = strtotime (date ('Y-m-d H:i:s')); // the current date
$key_date = strtotime (date ("2009-11-21 14:08:42"));
$diff = $now_date - $key_date;
$days = floor($diff/(60*60*24));
$hours = floor(($diff-($days*60*60*24))/(60*60));
print $days." ".$hours." difference";
?>
I prefer to use epoch/unix time deltas. Time represented in seconds and as such you can very quickly divide by 3600 for hours and divide by 24*3600=86400 for days.

Calculate the difference between date/times in PHP

I have a Date object ( from Pear) and want to subtract another Date object to get the time difference in seconds.
I have tried a few things but the first just gave me the difference in days, and the second would allow me to convert one fixed time to unix timestamp but not the Date object.
$now = new Date();
$tzone = new Date_TimeZone($timezone);
$now->convertTZ($tzone);
$start = strtotime($now);
$eob = strtotime("2009/07/02 17:00"); // Always today at 17:00
$timediff = $eob - $start;
** Note ** It will always be less than 24 hours difference.
Still gave somewhat wrong values but considering I have an old version of PEAR Date around, maybe it works for you or gives you an hint on how to fix :)
<pre>
<?php
require "Date.php";
$now = new Date();
$target = new Date("2009-07-02 15:00:00");
//Bring target to current timezone to compare. (From Hawaii to GMT)
$target->setTZByID("US/Hawaii");
$target->convertTZByID("America/Sao_Paulo");
$diff = new Date_Span($target,$now);
echo "Now (localtime): {$now->format("%Y-%m-%d %H:%M:%S")} \n\n";
echo "Target (localtime): {$target->format("%Y-%m-%d %H:%M:%S")} \n\n";
echo $diff->format("Diff: %g seconds => %C");
?>
</pre>
Are you sure that the conversion of Pear Date object -> string -> timestamp will work reliably? That is what is being done here:
$start = strtotime($now);
As an alternative you could get the timestamp like this according to the documentation
$start = $now->getTime();
To do it without pear, to find the seconds 'till 17:00 you can do:
$current_time = mktime ();
$target_time = strtotime (date ('Y-m-d'. ' 17:00:00'));
$timediff = $target_time - $current_time;
Not tested it, but it should do what you need.
I don't think you should be passing the entire Date object to strtotime. Use one of these instead;
$start = strtotime($now->getDate());
or
$start = $now->getTime();
Maybe some folks wanna have the time difference the facebook way. It tells you "one minute ago", or "2 days ago", etc... Here is my code:
function getTimeDifferenceToNowString($timeToCompare) {
// get current time
$currentTime = new Date();
$currentTimeInSeconds = strtotime($currentTime);
$timeToCompareInSeconds = strtotime($timeToCompare);
// get delta between $time and $currentTime
$delta = $currentTimeInSeconds - $timeToCompareInSeconds;
// if delta is more than 7 days print the date
if ($delta > 60 * 60 * 24 *7 ) {
return $timeToCompare;
}
// if delta is more than 24 hours print in days
else if ($delta > 60 * 60 *24) {
$days = $delta / (60*60 *24);
return $days . " days ago";
}
// if delta is more than 60 minutes, print in hours
else if ($delta > 60 * 60){
$hours = $delta / (60*60);
return $hours . " hours ago";
}
// if delta is more than 60 seconds print in minutes
else if ($delta > 60) {
$minutes = $delta / 60;
return $minutes . " minutes ago";
}
// actually for now: if it is less or equal to 60 seconds, just say it is a minute
return "one minute ago";
}

Categories