I have a database which contains posts that have both a creation date(unix timestamp) and a publication date(unix timestamp). I want to calculate the average time it takes a post to be published after its created. I guess im way off, but this is what i got so far:
$times = array();
foreach($posts as $post) {
$timeBetween = $post->publicationDate - $post->creationDate;
array_push($times, $timeBetween);
}
$average = array_sum($times) / count($times);
echo date("H:m:s",mktime(0,0,$average,0,0,0));
My optimal output would be something like: 1 day, 12 hours, 13 second..
Anyone?
Appreciate any help!
date() is not the correct tool for this job. date() doesn't understand a period of time like 2D 3H 27M, it only understands points in time.
In your code $average will contain a number of seconds, so you should finish with something like:-
$h = floor($average/3600);
$average -= $h*3600;
$m = floor($average/60);
$average -= $m*60;
$s = floor($average);
echo "$h:$m:$s";
Why don't you use the foreach-loop like this:
$time = 0;
foreach ( $posts as $post ) {
$time += $post->publicationDate - $post->creationDate;
}
$average = $time / count( $posts );
This way you don't need to use an array, and you got the same result.
If you want to show it like 2 days, 4 hours, 43 minutes and 2 seconds you can calculate it like this:
// 1 day = 24 hours * 60 minutes * 60 seconds = 86400 seconds
$days = floor( $average / 86400 );
$hours = floor( ( $average % 86400 ) / 3600 );
$minutes = floor( ( $average % 3600 ) / 60 );
$seconds = $average % 60;
echo $days . ' day' . ( $days > 0 ? 's' : '' ) . ', ';
echo $hours . ' hour' . ( $hours > 0 ? 's' : '' ) . ', ';
echo $minutes . ' minute' . ( $minutes > 0 ? 's' : '' ) . ', ';
echo $seconds . ' second' . ( $seconds > 0 ? 's' : '' );
Related
I am getting times in format of "hh:mm:ss".
I am doing sum of all those times. But here I am getting two hours more than required. so, where is the actual problem.
My code is like,
foreach($result as $key=>$value)
{
$total_markin_time[] = date('H:i:s', strtotime($value['clock_in']));
}
Getting result like,
00:33:41
16:15:22
11:06:59
11:03:59
11:13:38
15:43:34
11:29:35
foreach ( $total_markin_time as $time )
{
list( $g, $i, $s ) = explode( ':', $time );
//echo $g."-";
$total_markin_seconds += $g * 60 * 60;
$total_markin_seconds += $i * 60;
$total_markin_seconds += $s;
}
//echo $total_markin_seconds; exit;
$total_markin_hours = floor( $total_markin_seconds / 3600 );
$total_markin_seconds -= $total_markin_hours * 3600;
$total_markin_minutes = floor( $total_markin_seconds / 60 );
$total_markin_seconds -= $total_markin_minutes * 60;
When I am doing sum on this, I am gettin result 77:26:48.
Where is the problem?
Updated:
Is there any problem with floor that I have read like,
The floor() function rounds a number DOWN to the nearest integer, if necessary.
There is no error and it works right.
Calculation:
hours: 0+16+11+11+11+15+11 = 75 hours
minutes: 33+15+6+3+13+43+29 = 142 = 2 hours and 22 minutes
seconds: 41+22+59+59+38+34+35 = 288 = 4 minutes and 48 seconds
The result of sum is 77:26:48.
If you want to get just the sum of hours you should use something like this
foreach ( $total_markin_time as $time )
{
list( $g, $i, $s ) = explode( ':', $time );
$total_markin_hours += $g;
}
It's simple. All your times adds to:
288 s = 4m 48s
142 m = 2h 22m
75 h
Which in result (add hours + minutes + seconds) gives 77:26:48
You may think that You only add hours independent of minutes and seconds, but You have to add overflows of minutes and seconds.
I have array of items like this:
Array
(
[0] => 0:16:0
[1] => 0:0:8
[2] => 0:5:0
...
[n] => 0:3:1
)
There could be more arrays, they are symbolize
hours, minutes, seconds.
How can I calculate 0 + 1 + 2 + ... + n and to get final number of hours, minutes and seconds?
Try this code out
$arr = array('0:16:0', '25:12:5', '0:0:10', '0:5:0');
// converting all the times to seconds
$t_seconds = 0;
foreach ($arr as $v) {
sscanf($v, "%d:%d:%d", $hours, $minutes, $seconds);
$t_seconds += $hours * 3600 + $minutes * 60 + $seconds;
}
// condition if seconds calculated are negative
$sign = ($t_seconds < 0 ? '-' : '');
$t_seconds = abs($t_seconds);
// converting seconds, taking care of wrong minutes/seconds formats like 02:63:65
$hours = floor($t_seconds / 3600);
$minutes = floor(($t_seconds / 60) % 60);
$seconds = $t_seconds % 60;
// final format
$sum = $sign . sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds);
Result ($sum variable)
25:33:15
I solved by seperating hours, minutes, secounds as array from my foreach element. Then i call array, using array_sum
( thanks Rizier123 for point me on that function )
// receive values and calculate with current hours
$finalHourPause = array_sum($pauseArrayHours) . "\n";
$finalMinutePause = array_sum($pauseArrayMinutes) . "\n";
$finalSecoundsPause = array_sum($pauseArraySecounds) . "\n";
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.
Say I have a date function that produces
the output: 2011-10-03
PHP:
$todayDt = date('Y-m-d');
Anyway to get this date to instead show 2 days 1 hour ago
This function might be of some use. You might want to refine the check for months a bit, but this is just a quick example:
function RelativeTime($iTimestamp, $iLevel = 2)
{
!ctype_digit($iTimestamp)
&& $iTimestamp = strtotime($iTimestamp);
$iSecondsInADay = 86400;
$aDisplay = array();
// Start at the largest denominator
$iDiff = time() - $iTimestamp;
$aPeriods = array(
array('Period' => $iSecondsInADay * 356, 'Label' => 'year'),
array('Period' => $iSecondsInADay * 31, 'Label' => 'month'),
array('Period' => $iSecondsInADay, 'Label' => 'day'),
array('Period' => 3600, 'Label' => 'hour'),
array('Period' => 60, 'Label' => 'minute'),
array('Period' => 1, 'Label' => 'second'),
);
foreach ($aPeriods as $aPeriod)
{
$iCount = floor($iDiff / $aPeriod['Period']);
if ($iCount > 0)
{
$aDisplay[] = $iCount . ' ' . $aPeriod['Label'] . ($iCount > 1 ? 's' : '');
$iDiff -= $iCount * $aPeriod['Period'];
}
}
$iRange = count($aDisplay) > $iLevel
? $iLevel
: count($aDisplay);
return implode(' ', array_slice($aDisplay, 0, $iRange)) . ' ago';
}
And some examples of usage:
echo RelativeTime(time() - 102, 1);
// Will output: 1 minute ago
echo RelativeTime(time() - 2002);
// Will output: 33 minutes 22 seconds ago
echo RelativeTime(time() - 100002002, 6);
// Will output: 3 years 2 months 27 days 10 hours 20 minutes 2 seconds ago
echo RelativeTime('2011-09-05');
// Will output: 30 days 22 hours ago
This is post is just for a solution that does not use the DateTime::diff method. It also uses inputs with greater precision, so be aware of that.
$now = date('Y-m-d H:i:s');
$then = '2011-10-03 00:00:00'; // This will calculate the difference
// between now and midnight October 3rd
$nowTime = strtotime($now);
$thenTime = strtotime($then);
$diff = $nowTime - $thenTime;
$secs = $diff % 60;
$diff = intval($diff / 60);
$minutes = $diff % 60;
$diff = intval($diff / 60);
$hours = $diff % 24;
$diff = intval($diff / 24);
$days = $diff;
echo($days . ' days ' . $hours . ' hours ' . $minutes . ' minutes ' . $secs . ' seconds ago');
At the moment I tested it, the output was:
2 days 16 hours 6 minutes 2 seconds ago
If all you want are the days and hours, then you can just choose to echo those two out:
echo($days . ' days ' . $hours . ' hours ago');
2 days 16 hours ago
Say I have the following 2 dates, a start date and end date:
Year-Month-Day Hours:Minutes:Seconds
Start Date: 2010-12-03 14:04:41
Expiry Date: 2010-12-06 12:59:59
How could I, using PHP subtract the two dates and be left with something like:
Difference: -3 days, 2 minutes and 18 seconds (If expiry date is past 3 days for example).
http://www.php.net/manual/en/datetime.diff.php
<?php
$datetime1 = date_create('2009-10-11');
$datetime2 = date_create('2009-10-13');
$interval = date_diff($datetime1, $datetime2);
echo $interval->format('%R%d days');
//result will be +2 days
?>
I hope that is what you are looking for.
This is based on numerous online examples; you'll see similar code all around if you get your google on.
function timeSince($dateFrom, $dateTo) {
// array of time period chunks
$chunks = array(
array(60 * 60 * 24 * 365 , 'year'),
array(60 * 60 * 24 * 30 , 'month'),
array(60 * 60 * 24 * 7, 'week'),
array(60 * 60 * 24 , 'day'),
array(60 * 60 , 'hour'),
array(60 , 'minute'),
);
$original = strtotime($dateFrom);
$now = strtotime($dateTo);
$since = $now - $original;
$message = ($now < $original) ? '-' : null;
// If the difference is less than 60, we will show the seconds difference as well
if ($since < 60) {
$chunks[] = array(1 , 'second');
}
// $j saves performing the count function each time around the loop
for ($i = 0, $j = count($chunks); $i < $j; $i++) {
$seconds = $chunks[$i][0];
$name = $chunks[$i][1];
// finding the biggest chunk (if the chunk fits, break)
if (($count = floor($since / $seconds)) != 0) {
break;
}
}
$print = ($count == 1) ? '1 ' . $name : $count . ' ' . $name . 's';
if ($i + 1 < $j) {
// now getting the second item
$seconds2 = $chunks[$i + 1][0];
$name2 = $chunks[$i + 1][1];
// add second item if it's greater than 0
if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0) {
$print .= ($count2 == 1) ? ', 1 ' . $name2 : ', ' . $count2 . ' ' . $name2 . 's';
}
}
return $message . $print;
}
It was intended to show the difference between a given time and the current time, but I've made slight changes to show the difference between two times instead. You may wish to change the output from a postfix of ' ago' to a prefix of 'Difference: '.