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
Related
I am trying to transform a unix timestamp into a human readable string so i can show how long ago a user signed up.
Here is my data:
mysql> select createdate as unixtimestamp,date_format(from_unixtime(createdate),'%e %b %Y') as dateformatted from users where userid=40645;
+---------------+---------------+
| unixtimestamp | dateformatted |
+---------------+---------------+
| 1162642968 | 4 Nov 2006 |
+---------------+---------------+
1 row in set (0.00 sec)
mysql>
Ok so here is where the problem resides. I found 3 different functions on the internet that return a human readable string from a unix timestamp. All 3 failed to work.
I'd like someone to look at these functions and help me figure out how to fix one of them to return the correct human readable string.
On with the show!
Here is function #1:
function getElapstedTimeHumanReadable($time)
{
$names = array("seconds", "minutes", "hours", "days", "months", "years");
$values = array(1, 60, 3600, 24 * 3600, 30 * 24 * 3600, 365 * 24 * 3600);
$time = time()-$time;
for($i = count($values) - 1; $i > 0 && $time < $values[$i]; $i--);
if($i == 0) {
$timestamp = intval($time / $values[$i]) . " " . $names[$i];
} else {
$t1 = intval($time / $values[$i]);
$t2 = intval(($time - $t1 * $values[$i]) / $values[$i - 1]);
$timestamp= "$t1 " . $names[$i] . ", $t2 " . $names[$i - 1];
}
return $timestamp;
}
My return value for this function is "Joined 1 days, 17 hours ago"
Clearly this isn't correct.
Here is function #2:
function getElapsedTimeHumanReadable($time)
{
$time = time() - $time;
$points = array(
'year' => 31556926,
'month' => 2629743,
'week' => 604800,
'day' => 86400,
'hour' => 3600,
'minute' => 60,
'second' => 1
);
foreach($points as $point => $value)
{
if($elapsed = floor($time/$value) > 0)
{
$s = $elapsed>1?'s':'';
$timestamp = "$elapsed $point$s";
break;
}
}
return $timestamp;
}
My return value for this function is "Joined 1 day ago
And finally, here is function #3:
function getElapsedTimeHumanReadable($time)
{
$etime=time()-$time;
if ($etime < 1)
{
return '0 seconds';
}
$a = array( 365 * 24 * 60 * 60 => 'year',
30 * 24 * 60 * 60 => 'month',
24 * 60 * 60 => 'day',
60 * 60 => 'hour',
60 => 'minute',
1 => 'second'
);
$a_plural = array( 'year' => 'years',
'month' => 'months',
'day' => 'days',
'hour' => 'hours',
'minute' => 'minutes',
'second' => 'seconds'
);
foreach ($a as $secs => $str)
{
$d = $etime / $secs;
if ($d >= 1)
{
$r = round($d);
return $r . ' ' . ($r > 1 ? $a_plural[$str] : $str) . ' ago';
}
}
}
So theres my code and my data. Not quite sure why none seem to work. I tried looking at the code but I cannot figure out how to solve it.
Whats interesting is they all say 2 days, but my timestamp appears to show 2006.
Thanks for the help.
$time = 1162642968 ;
$date = new DateTime( );
$date->setTimestamp( $time );
$today = new DateTime( 'now', new DateTimeZone( "Europe/Rome" ) );
$diff = $today->diff( $date);
echo "Year: " . $diff->y . " - Month: " . $diff->m . " - Days: " . $diff->d . " - Hours: " . $diff->h;
EXAMPLE
As suggested I'll add explanation, even if I think it is really self explain.
$date = new DateTime() create the object and $date->setTimestamp( $time ) is used to put that date at a value from the mysql timestamp.
$today is created pointing at the actual date.
$date->diff() create a DateInterval Object ( http://php.net/manual/en/class.dateinterval.php ) that contains all the necessary datas.
If you want to solve this yourself, you should calculate the difference and base it on those values. I haven't tested RiccardoC's Answer, but this seems as a nice way to go.
As I see in your posting, you calculate a year always as 365 days, so if you don't want to go in a deep detail with time zones, extra hours, extra days, different month lengths etc, you could use something simple as that:
function getElapsedTimeHumanReadable($timestamp) {
$diff = time() - $timestamp;
$years = intval($diff/31536000); //seconds in a year 60*60*24*365
$diff -= ($years*31536000);
$months = intval($diff/2592000); //seconds in a month 60*60*24*30
$diff -= ($months*2592000);
$days = intval($diff/86400); //seconds in a day 60*60*24
return $years." years, ".$months." months, ".$days." days ago";
}
echo getElapsedTimeHumanReadable(1162642968); // November 4th, 2006
Echos 9 years, 0 months, 17 days ago
I'm making an automatic countdown to an event that starts 2-3 times a day on diffrent times.
The event starts every 7 hours, so one day there are 4 events and the other 3.
Example:
http://i.stack.imgur.com/IvYbh.png
$monday = array( '02:00', '09:00', '16:00', '23:00' );
$tuesday = array( '06:00', '13:00', '20:00' );
$wednesday = array( '03:00', '10:00', '17:00' );
$thursday = array( '00:00', '07:00', '14:00', '21:00' );
$friday = array( '04:00', '11:00', '18:00' );
$saturday = array( '01:00', '08:00', '15:00', '22:00' );
$sunday = array( '05:00', '12:00', '19:00' );
How to make the countdown run to the next event?
Example: if it is Monday, 01:30, it should say 30min left
I already made the countdown part:
$hours = floor($this->sec / 3600);
$minutes = floor(($this->sec / 60) % 60);
$seconds = $this->sec % 60;
return "$hours" . ' hours ' . "$minutes" . ' minutes ' . "$seconds" . ' seconds';
Update: I know that the PHP won´t update just on itself. I will refresh the page manually.
function days_hours_minutes_from_now($date)
{
$now = time();
$your_date = strtotime($date);
$datediff = $your_date - $now;
echo "days: " .floor($datediff/(60*60*24));
echo " hours: " .floor($datediff/(60*60)) % 24; //hours
echo " minutes: " .floor($datediff/(60)) % 60; //minutes
echo " seconds: " .$datediff % 60; //seconds
}
days_hours_minutes_from_now("2015-08-19 13:52:28");
days: 1 hours: 0 minutes: 14 seconds: 56
Hasn't been tested thoroughly, but should be close to what you're looking for.
You need to compare the time against when the event starts to get a countdown.
However, as RiggsFolly rightly pointed out, unless you do this in javascript, your countdown isn't going to update in the user's browser unless they refresh the page.
Edit:
Now, if you wanted to ensure you always returned the time remaining until the next event, then you can loop through a series of dates, sorted in ascending order, and return the first result where the day is a non-negative value. If any date exceeds the current date/time, day will equal -1
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' : '' );
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.
I'm working with a function I found to do this, but I'm trying to make it work with a GMT utc timestamp:
EDIT:
Maybe my issue is with how i'm "converting" the user input time to GMT...
I was doing
$the_user_input_date = strtotime('2011-07-20T01:13:00');
$utctime = gmdate('Y-m-d H:i:s',$the_user_input_date);
Does gmdate('Y-m-d H:i:s',$the_user_input_date); not actually "convert" it to gmt? does it just format it? Maybe thats my issue.
Here's what the times I can supply would look like:
//local time in GMT
2011-07-20T01:13:00
//future time in GMT
2011-07-20T19:49:39
I'm trying to get this to work like:
Started 36 mins ago
Will start in 33 mins
Will start in 6 hrs 21 mins
Will start in 4 days 4 hrs 33 mins
Here's what im working with so far:
EDIT: new php code im working with, seems to ADD 10 HOURS on to my date. Any ideas? I updated it here:
function ago($from)
{
$to = time();
$to = (($to === null) ? (time()) : ($to));
$to = ((is_int($to)) ? ($to) : (strtotime($to)));
$from = ((is_int($from)) ? ($from) : (strtotime($from)));
$units = array
(
"year" => 29030400, // seconds in a year (12 months)
"month" => 2419200, // seconds in a month (4 weeks)
"week" => 604800, // seconds in a week (7 days)
"day" => 86400, // seconds in a day (24 hours)
"hour" => 3600, // seconds in an hour (60 minutes)
"minute" => 60, // seconds in a minute (60 seconds)
"second" => 1 // 1 second
);
$diff = abs($from - $to);
$suffix = (($from > $to) ? ("from now") : ("ago"));
foreach($units as $unit => $mult)
if($diff >= $mult)
{
$and = (($mult != 1) ? ("") : ("and "));
$output .= ", ".$and.intval($diff / $mult)." ".$unit.((intval($diff / $mult) == 1) ? ("") : ("s"));
$diff -= intval($diff / $mult) * $mult;
}
$output .= " ".$suffix;
$output = substr($output, strlen(", "));
return $output;
}
#Jason
I tried what you suggested here:
function ago($dateto)
{
$datetime1 = new DateTime( $dateto);
$datetime2 = new DateTime();
$interval = $datetime1->diff($datetime2);
// print_r($interval);
$format = '';
if ($interval->h) {
$format .= ' %h ' . ($interval->h == 1 ? 'hour' : 'hours');
}
if ($interval->i) {
$format .= ' %i ' . ($interval->i == 1 ? 'minute' : 'minutes');
}
// more logic for each interval
if ($format) {
echo $interval->format($format), ' ago';
}
else {
echo 'now';
}
}
It always seems to add 10 hours on to my time.
Any ideas what could be going on?
Maybe an error lies with how I'm saving the target time?
When someone submits a time its converted and stored like this
The user submitted time will always start out looking like this as their local time:
07/20/2011 11:00 pm
Then:
$time = mysql_real_escape_string($_POST['time']);
$the_date = strtotime($time);
//make user input time into GMT time
$utctime = gmdate('Y/m/d H:i:s',$the_date);
$query = "INSERT INTO $table (time) VALUES ('$utctime');";
mysql_query($query);
Provided you have access to PHP >= 5.3 I'd recommend DateTime::diff(). The DateInterval returned gives you all the parts you would need for display as well as has its own methods, such as format().
Here's a sample to give you an idea. There are more complete samples in the comments of the PHP documentation links.
<?php
$datetime1 = new DateTime('2011-07-20');
$datetime2 = new DateTime();
$interval = $datetime1->diff($datetime2);
// print_r($interval);
$format = '';
if ($interval->h) {
$format .= ' %h ' . ($interval->h == 1 ? 'hour' : 'hours');
}
if ($interval->i) {
$format .= ' %i ' . ($interval->i == 1 ? 'minute' : 'minutes');
}
// more logic for each interval
if ($format) {
echo $interval->format($format), ' ago';
}
else {
echo 'now';
}
It outputs (on my system):
22 hours 10 minutes ago
Your $datefrom is a string, but $dateto is an int. You can't subtract them that way.
Instead of:
$datefrom=gmdate("Y/m/d\TH:i:s\Z");
Do:
$datefrom=time();
PS. I did not check the rest of the code.