Hide hours and mins if they are zero in the function provided - php

The function below outputs hours:0 whether the time is <1 hour or mins:0 when mins<1.
How can I show only the variables that are not zero?
Thank you.
function time_difference($endtime){
$hours =date("G",$endtime);
$mins =date("i",$endtime);
$secs =date("s",$endtime);
$diff="'hours': ".$hours.",'mins': ".$mins.",'sec': ".$secs;
return $diff;
}
$end_time =strtotime("+7 hours") - strtotime($entry->pubDate);
$difference = time_difference($end_time);
echo $difference;

Another possible approach:
function time_difference($endtime){
$times=array(
'hours' => date("G",$endtime),
'mins' => date("i",$endtime),
'secs' => date("s",$endtime),
);
//added a "just a moment ago" feature for you
if (intval($times['hours'], 10) == 0
&& intval($times['mins'], 10) == 0) {
return "just a moment ago";
}
$diff='';
foreach ($times as $k=>$v) {
$diff.=empty($diff) ? '' : ',';
$diff.=intval($v, 10) == 0 ? '' : "'$k':$v";
}
return $diff;
}

Use the ? operator.
$diff=($hours > 0) ? "'hours': ".$hours : "";
$diff=$diff.($minutes > 0) ? etc...

For larger time ranges, you'd better use maths instead of using date():
function time_difference($endtime){
// hours can get over 23 now, $endtime is in seconds
$hours = floor($endtime / 3600);
// modulo (%) already rounds down, not need to use floor()
$mins = $endtime / 60 % 60;
// the remainder of $endtime / 60 are seconds in a minute
$secs = $endtime % 60;
// this array holds the hour, minute and seconds if greater than 0
$diff = array();
if ($hours) $diff[] = "'hours': $hours";
if ($mins) $diff[] = "'mins': $mins";
if ($secs) $diff[] = "'sec': $secs";
// join the values with a comma
$diff = implode(',', $diff);
if (!$diff) { // hours, mins and secs are zero
$diff = "just a moment ago";
}
return $diff;
}
The below function would only return hours in the range 0 - 23. If the time exceeds a day, hours become zero:
function time_difference($endtime){
$hours = (int)date("G",$endtime);
$mins = (int)date("i",$endtime);
$secs = (int)date("s",$endtime);
// this array holds the hour, minute and seconds if greater than 0
$diff = array();
if ($hours) $diff[] = "'hours': $hours";
if ($mins) $diff[] = "'mins': $mins";
if ($secs) $diff[] = "'sec': $secs";
// join the values with a comma
$diff = implode(',', $diff);
if (!$diff) { // hours, mins and secs are zero
$diff = "just a moment ago";
}
return $diff;
}
(int) is needed to turn the string returned by date() into a string. "01" becomes 1 and "00" becomes "0" using this.

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

Difference between durations

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);

PHP subtracting Time getting negative results

I want to get the Time in and Time out then get the rendered hours, minutes and seconds but im having a problem on subtracting time here is a sample result
Time in: 10:00:33
Time out: 10:01:30
Total Hours rendered: 0
Total Minutes rendered: 1
Total Seconds rendered: -3
in the sample above it returns 1 minute already even though its not 1 minute yet and in the seconds it returns a negative value
here is my code
$time_out = date("H:i:s");
$nerd->time_out = $time_out;
$time_o = explode(":", $time_out);
$time = explode(":", $nerd->time_in);
$hours = $time_o[0] - $time[0];
$minutes = $time_o[1] - $time[1];
$seconds = $time_o[2] - $time[2];
if($minutes < 2){
$minutes_r = 0;
}else if($minutes <= 15){
$minutes_r = 15;
}else if($minutes <= 30){
$minutes_r = 30;
}else if($minutes <= 45){
$minutes_r = 45;
}else{
$minutes_r = 0;
}
in my code I explode the time to get values in hours, minutes and seconds.
Can anyone suggest a better way of doing this so there will be no negative results?
add this in middle:
if($seconds < 0) {
$seconds += 60;
$minutes--;
}
if($minutes < 0) {
$minutes += 60;
$hours--;
}

Trouble using percent sign operator (%) (PHP)

I'm attempting to convert 7500 seconds to minutes, and then the minutes to hours. If it comes out to 2 hours and 5 minutes, as in this example, I'd like to display it as "2 hours and 5 minutes". If its 2 hours even, I just want it to display "2 hours".
7500 divided by 60 divided by 60 comes out to 2.083 (3 repeated). Why does the % return 0? How can I determine if its hours exactly, or if there are minutes to display?
die("Test: " . ((7500 / 60) / 60) % 1);
For conversion, you can use:
function secondsToWords($seconds)
{
/*** return value ***/
$ret = "";
/*** get the hours ***/
$hours = intval(intval($seconds) / 3600);
if($hours > 0)
{
$ret .= "$hours hours ";
}
/*** get the minutes ***/
$minutes = bcmod((intval($seconds) / 60),60);
if($hours > 0 || $minutes > 0)
{
$ret .= "$minutes minutes ";
}
/*** get the seconds ***/
$seconds = bcmod(intval($seconds),60);
$ret .= "$seconds seconds";
return $ret;
}
echo secondsToWords(7500);
Because that is the modulus operator, which gives the remainder of the division.
You want to use /, the division operator, that returns a float. See here
I've created a nice function for that a while ago. It also does years and months (and anything you'd like) if you want.
Source + examples: http://hotblocks.nl/tests/time_ago.php
Function:
<?php
function time_ago( $f_seconds, $f_size = 2, $f_factor = 1.6 ) {
$units = array(
86400*365.25 => array(' year', ' years'),
86400*30 => array(' month', ' months'),
86400*7 => array(' week', ' weeks'),
86400 => array(' day', ' days'),
3600 => array(' hour', ' hours'),
60 => array(' minute', ' minutes'),
1 => array(' second', ' seconds'),
);
if ( isset($GLOBALS['g_units']) && is_array($GLOBALS['g_units']) ) {
$units = $GLOBALS['g_units'];
}
$timeAgo = array();
$seconds = (int)$f_seconds;
foreach ( $units AS $range => $unit ) {
if ( 1 == $range || $seconds >= $range * $f_factor ) {
is_array($unit) || $unit = array($unit, $unit);
$last = count($timeAgo) == $f_size-1;
$round = $last ? 'round' : 'floor';
$num = $round($seconds / $range);
$timeAgo[] = $num . $unit[(int)(1 != $num)];
if ( $last ) {
break;
}
$seconds -= $num * $range;
}
}
$separator = isset($GLOBALS['g_separator']) ? $GLOBALS['g_separator'] : ', ';
return implode($separator, $timeAgo);
}
?>
That's the way the mod (%) operator works. Every integer is divisible by 1, so
n % 1 = 0
for all integral n.
What are you trying to do with the % operator?
Whatever it is, you probably want to apply it on an integral value, like the number of seconds. It doesn't work for non-integral values; they are promoted to int values before the operator is applied.

How to convert seconds to time format? [duplicate]

This question already has answers here:
Convert seconds to Hour:Minute:Second
(30 answers)
Closed 9 years ago.
For some reason I convert a time format like: 03:30 to seconds 3*3600 + 30*60, now. I wanna convert it back to its first (same) format up there. How could that be?
My attempt:
3*3600 + 30*60 = 12600
12600 / 60 = 210 / 60 = 3.5, floor(3.5) = 3 = hour
Now, what about the minutes?
Considering the value can be like 19:00 or 02:51.
I think you got the picture.
And by the way, how to convert 2:0 for example to 02:00 using RegEx?
This might be simpler
gmdate("H:i:s", $seconds)
PHP gmdate
$hours = floor($seconds / 3600);
$mins = floor($seconds / 60 % 60);
$secs = floor($seconds % 60);
If you want to get time format:
$timeFormat = sprintf('%02d:%02d:%02d', $hours, $mins, $secs);
If the you know the times will be less than an hour, you could just use the date() or $date->format() functions.
$minsandsecs = date('i:s',$numberofsecs);
This works because the system epoch time begins at midnight (on 1 Jan 1970, but that's not important for you).
If it's an hour or more but less than a day, you could output it in hours:mins:secs format with `
$hoursminsandsecs = date('H:i:s',$numberofsecs);
For more than a day, you'll need to use modulus to calculate the number of days, as this is where the start date of the epoch would become relevant.
Hope that helps.
Maybe the simplest way is:
gmdate('H:i:s', $your_time_in_seconds);
Let $time be the time as number of seconds.
$seconds = $time % 60;
$time = ($time - $seconds) / 60;
$minutes = $time % 60;
$hours = ($time - $minutes) / 60;
Now the hours, minutes and seconds are in $hours, $minutes and $seconds respectively.
Another solution that will give you the days, hours, minutes, and seconds for a passed-in seconds value:
function seconds_to_time($secs)
{
$dt = new DateTime('#' . $secs, new DateTimeZone('UTC'));
return array('days' => $dt->format('z'),
'hours' => $dt->format('G'),
'minutes' => $dt->format('i'),
'seconds' => $dt->format('s'));
}
print_r(seconds_to_time($seconds_value);
Extra logic will be needed for 'days' if the time is expected to be more than one year. Use str_pad() or ltrim() to add/remove leading zeros.
ITroubs answer doesn't deal with the left over seconds when you want to use this code to convert an amount of seconds to a time format like hours : minutes : seconds
Here is what I did to deal with this:
(This also adds a leading zero to one-digit minutes and seconds)
$seconds = 3921; //example
$hours = floor($seconds / 3600);
$mins = floor(($seconds - $hours*3600) / 60);
$s = $seconds - ($hours*3600 + $mins*60);
$mins = ($mins<10?"0".$mins:"".$mins);
$s = ($s<10?"0".$s:"".$s);
$time = ($hours>0?$hours.":":"").$mins.":".$s;
$time will contain "1:05:21" in this example.
If you were to hardcode it you would use modulus to extract the time as others suggested.
If you are returning the seconds from MySQL database, assuming you don't need the data in seconds format in your app, there is a much cleaner way to do it, you can use MySQL's SEC_TO_TIME and it will return time in hh:mm:ss format.
Eg.
SELECT SEC_TO_TIME(my_seconds_field) AS my_timestring;
Sorry this is too late but maybe useful
function mediaTimeDeFormater($seconds)
{
if (!is_numeric($seconds))
throw new Exception("Invalid Parameter Type!");
$ret = "";
$hours = (string )floor($seconds / 3600);
$secs = (string )$seconds % 60;
$mins = (string )floor(($seconds - ($hours * 3600)) / 60);
if (strlen($hours) == 1)
$hours = "0" . $hours;
if (strlen($secs) == 1)
$secs = "0" . $secs;
if (strlen($mins) == 1)
$mins = "0" . $mins;
if ($hours == 0)
$ret = "$mins:$secs";
else
$ret = "$hours:$mins:$secs";
return $ret;
}
echo mediaTimeDeFormater(216.064000);//3:36
something like this?
if(is_numeric($time)){
$value = array(
"years" => 0, "days" => 0, "hours" => 0,
"minutes" => 0, "seconds" => 0,
);
if($time >= 31556926){
$value["years"] = floor($time/31556926);
$time = ($time%31556926);
}
if($time >= 86400){
$value["days"] = floor($time/86400);
$time = ($time%86400);
}
if($time >= 3600){
$value["hours"] = floor($time/3600);
$time = ($time%3600);
}
if($time >= 60){
$value["minutes"] = floor($time/60);
$time = ($time%60);
}
$value["seconds"] = floor($time);
return (array) $value;
} else{
return (bool) FALSE;
}
grabbed from: http://www.ckorp.net/sec2time.php
Use modulo:
$hours = $time_in_seconds / 3600;
$minutes = ($time_in_seconds / 60) % 60;
just one small additional example
requested time in miliseconds
// ms2time( (microtime(true) - ( time() - rand(0,1000000) ) ) );
// return array
function ms2time($ms){
$return = array();
// ms
$return['ms'] = (int) number_format( ($ms - (int) $ms), 2, '', '');
$seconds = (int) $ms;
unset($ms);
if ($seconds%60 > 0){
$return['s'] = $seconds%60;
} else {
$return['s'] = 0;
}
if ( ($minutes = intval($seconds/60))){
$return['m'] = $minutes;
}
if (isset($return['m'])){
$return['h'] = intval($return['m'] / 60);
$return['m'] = $return['m'] % 60;
}
if (isset($return['h'])){
$return['d'] = intval($return['h'] / 24);
$return['h'] = $return['h'] % 24;
}
if (isset($return['d']))
$return['mo'] = intval($return['d'] / 30);
foreach($return as $k=>$v){
if ($v == 0)
unset($return[$k]);
}
return $return;
}
// ms2time2string( (microtime(true) - ( time() - rand(0,1000000) ) ) );
// return array
function ms2time2string($ms){
$array = array(
'ms' => 'ms',
's' => 'seconds',
'm' => 'minutes',
'h' => 'hours',
'd' => 'days',
'mo' => 'month',
);
if ( ( $return = ms2time($ms) ) && count($ms) > 0){
foreach($return as $key=>$data){
$return[$key] = $data .' '.$array[$key];
}
}
return implode(" ", array_reverse($return));
}
Here is another way with leading '0' for all of them.
$secCount = 10000;
$hours = str_pad(floor($secCount / (60*60)), 2, '0', STR_PAD_LEFT);
$minutes = str_pad(floor(($secCount - $hours*60*60)/60), 2, '0', STR_PAD_LEFT);
$seconds = str_pad(floor($secCount - ($hours*60*60 + $minutes*60)), 2, '0', STR_PAD_LEFT);
It is an adaptation from the answer of Flaxious.
If You want nice format like: 0:00:00 use str_pad() as #Gardner.
1 day = 86400000 milliseconds.
DecodeTime(milliseconds/86400000,hr,min,sec,msec)
Ups! I was thinking in delphi, there must be something similar in all languages.

Categories