displaying relevant date formats in months days minutes or seconds? - php

im trying to convert a mysql timestamp to time in months or days or hours or minutes.
so the output will look like this:
added 1 month ago / added: 0 hours ago / added: 21 minutes ago / added 30 seconds ago
so i only want one format of time depending on how many minutes or how many hours or how many days etc, so 60 minutes converts to 1 hour ago or 24 hours converts to 1 day ago and 48 hours converts to 2 dayS ago.
so far i have this code:
<?
$datetime1 = new DateTime();
$datetime2 = new DateTime ($news['date_added']);
$interval = $datetime1->diff($datetime2);
str_replace('0 hours', '', $variable);
echo $interval->format('%h hours %i minutes');
?>
and this outputs the following:
added 0 hours ago 57 minutes ago.
can someone help me or show me what id need to do in order to get the formats to display right, im really new to php and am not sure how i can do this. thank you.

From http://php.net/manual/en/ref.datetime.php
Just change $precision to 1 when you call the function and add in whatever text you want to come before and after the date. You'll have to make sure you convert your date objects to timestamps, but that shouldn't be a problem for you.
/**
* this code assumes php >= 5.1.0. if using < 5.1, read
* php.net/strtotime and change the condition for checking
* for failure from strtotime()
*/
// $t1, $t2: unix times, or strtotime parseable
// $precision: max number of units to output
// $abbr: if true, use "hr" instead of "hour", etc.
function date_diff ($t1, $t2, $precision = 6, $abbr = false) {
if (preg_match('/\D/', $t1) && ($t1 = strtotime($t1)) === false)
return false;
if (preg_match('/\D/', $t2) && ($t2 = strtotime($t2)) === false)
return false;
if ($t1 > $t2)
list($t1, $t2) = array($t2, $t1);
$diffs = array(
'year' => 0, 'month' => 0, 'day' => 0,
'hour' => 0, 'minute' => 0, 'second' => 0,
);
$abbrs = array(
'year' => 'yr', 'month' => 'mth', 'day' => 'day',
'hour' => 'hr', 'minute' => 'min', 'second' => 'sec'
);
foreach (array_keys($diffs) as $interval) {
while ($t2 >= ($t3 = strtotime("+1 ${interval}", $t1))) {
$t1 = $t3;
++$diffs[$interval];
}
}
$stack = array();
foreach ($diffs as $interval => $num)
$stack[] = array($num, ($abbr ? $abbrs[$interval] : $interval) . ($num != 1 ? 's' : ''));
$ret = array();
while (count($ret) < $precision && ($item = array_shift($stack)) !== null) {
if ($item[0] > 0)
$ret[] = "{$item[0]} {$item[1]}";
}
return implode(', ', $ret);
}
$t1 = 'Feb 4, 2008 12:16:00';
$t2 = 'Jul 3, 2006 16:15:30';
echo date_diff($t1, $t2), "\n",
date_diff($t1, $t2, 3), "\n",
date_diff($t1, $t2, 2, true), "\n";
?>

Here is a possible solution. You format the time difference as a string with months-days-hours-minutes-seconds, then look through that string for the first non-zero number: that's the one you want...
$mdhms = explode('-',$interval->format('%m-%d-%H-%i-%s'));
$labels = Array(' months', ' days', ' hours', ' minutes', ' seconds');
$i = 0;
foreach($mdhms as $t){
if($t > 0) break;
$i+=1;
}
if ($i < 5) echo "It happened ".$t.$labels[$i]." ago";
else echo "It is happening right now!"

Related

In PHP, how do I get the accurate (not approximate) total individual number of weeks, months and years between two timestamps?

I can do it for days like this:
$d1 = new DateTime('2000-01-01 12:00:00');
$d2 = new DateTime('2020-01-01 12:00:00');
$diff = $d2->diff($d1);
echo $diff->days;
In other words, it works for days. However, the DateTime/DateInterval class has only a $days variable -- these are expected but don't exist:
$diff->weeks;
$diff->months;
$diff->years;
Reading the manual, you might at first glance be deceived into thinking that it does have these attributes: https://www.php.net/manual/en/class.dateinterval.php
public integer $y ;
public integer $m ;
public integer $d ;
public integer $h ;
public integer $i ;
public integer $s ;
public float $f ;
public integer $invert ;
public mixed $days ;
The y, m, d, h, i, s there are not "individual totals", but depend on each other. For example, if the time span is exactly one year, the $y will be 1, but all of the other ones will be 0, instead of their respective representations (12 months, 52 weeks, etc.).
They treat days specially for some reason by including the $days variable, which does show the actual total number of days. I want that for weeks, months and years too.
I already know how to "estimate" the number of weeks/months/years between two timestamps, by using simple math and fixed variables representing the average number of seconds in each time unit. Since this doesn't take into consideration all the complexities of "traversing" the calendar format(s), such as leap years, varying days in different months, and many other small/complex details, you don't get the exact number that way.
I want to know the exact total number of weeks between two timestamps, and the same thing for years and months, independent of each other.
This will return the exact difference between two days hope this will help you.
$time_diffrence=getDiffrenceBetweenTwoDays($date1,$date2);
function getDiffrenceBetweenTwoDays($date1,$date2){
$etime = strtotime($date1) - strtotime($date2;
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) .'' ;
}
}
}
Replace %a with any of the following at this link:
FORMATS
$d1 = date_create('2000-01-01 12:00:00');
$d2 = date_create('2020-01-01 12:00:00');
$diff = date_diff($d1, $d2);
$days = $diff->format('%a');
echo $days; // 7305

Format datetime interval with a minimum difference

I found this really nice PHP script that converts any datetime into a relative string, for example:
'2013-05-01 00:22:35' -> '3 months ago'
It's really cool, but I would like to "trick" the function so that even if the date is, let's say, 20 minutes before, the function returns 1 hour ago instead of 20 minutes ago. Thus, I want to enforce a minimum difference of 1 hour, even when the difference is less than that.
For reference, here is the function.
function time_elapsed_string($datetime, $full = false) {
$now = new DateTime;
$ago = new DateTime($datetime);
$diff = $now->diff($ago);
$diff->w = floor($diff->d / 7);
$diff->d -= $diff->w * 7;
$string = array(
'y' => 'year',
'm' => 'month',
'w' => 'week',
'd' => 'day',
'h' => 'hour',
'i' => 'minute',
's' => 'second',
);
foreach ($string as $k => &$v) {
if ($diff->$k) {
$v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
} else {
unset($string[$k]);
}
}
if (!$full) $string = array_slice($string, 0, 1);
return $string ? implode(', ', $string) . ' ago' : 'just now';
}
I tried a lot of different things, but nothing really worked.
How can I enforce a minimum difference of 1 hour?
After you have figured out the difference, simply check if the largest difference is only minutes or seconds. If so, return the minimum of 1 hour that you require.
// here is your foreach loop
// check if less than 1 hour, if so, return that
$keys = array_keys($string);
if ($keys[0] === 'i' || $keys[0] === 's') {
return 'less than 1 hour ago';
}
Try it online!
I put the time of posting the question in this example. When you look at it more than 1 hour after that, you'll have to modify the test case to a DateTime that is less than 1 hour ago in UTC time.
Test cases. It is now 2017-06-10 12:45:00 in UTC.
time_elapsed_string("2017-06-10 12:11:19"); // less than 1 hour ago
time_elapsed_string("2017-06-10 11:44:00"); // 1 hour ago
time_elapsed_string("2017-06-10 11:44:00", true); // 1 hour, 1 minute ago
time_elapsed_string("2017-06-09 11:45:00", true); // 1 day, 1 hour ago
time_elapsed_string("2017-06-09 11:45:00"); // 1 day ago
days : If the DateInterval object was created by DateTime::diff(), then this is the total number of days between the start and end dates. Otherwise, days will be FALSE. http://php.net/manual/en/class.dateinterval.php
Since we know it won't be false, it will evaluate to false only when 0.
if($diff->days) {
$diff->w = floor($diff->d / 7);
$diff->d -= $diff->w * 7;
} else /* less than a day's difference */ if(!$diff->h && ($diff->i || $diff->s)) /* less than an hour's difference */ {
$diff->h = 1;
$diff->i = 0;
$diff->s = 0;
}
I've added some refinements to your original code. I've also removed the full option from your function as I don't think you intend to use it for your case. If my inline comments fail to explain my process, just ask.
Code: (Demo)
function time_elapsed_string($datetime){
$now=new DateTime; // current datetime
$ago=new DateTime($datetime); // user datetime
if($now<$ago){return "Unexpected future datetime value";}
$diff=$now->diff($ago); // datetime difference
$diff->w=intval(floor($diff->d/7)); // add weeks to diff output
$diff->d-=$diff->w*7; // reduce days based on weeks calculation
$units=[
'y'=>'year',
'm'=>'month',
'w'=>'week',
'd'=>'day',
'h'=>'hour'
];
$kept_diff=array_intersect_key((array)$diff,$units); // omit unwanted elements of diff()'s output
if(!max($kept_diff)){ // if y, m, w, d, & h all = 0, show default
return 'default: 1 hour ago'; // inserted "default: " for demo. Remove in production.
}else{
$diffs=array_filter(array_merge($units,$kept_diff)); // sort by $units order, then omit elements with 0 value
return current($diffs).' '.$units[key($diffs)].(current($diffs)>1?'s':'').' ago'; // return highest unit data in plain English
}
}
echo time_elapsed_string('2017-06-30 02:22:35'); // output: 3 weeks ago

cannot get human readable text from various functions discovered

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

Subtracting time to post how many minutes ago [duplicate]

This question already has answers here:
Calculate relative time in C#
(41 answers)
How to display "12 minutes ago" etc in a PHP webpage? [closed]
(3 answers)
Closed 8 years ago.
So my current $item['date'] function gets the time and date of the post in this format Y-m-d H:i:s.
I want to display how many minutes was the post posted or if it is more than 24 hours, how many days ago was it posted OR like 0 days and 20 hours ago? something like that
Why doesn't the minus operator work here my code?
My current code:
<p><?php echo date('Y-m-d H:i:s') - $item['date'] ?> minutes ago</p>
I usually use this function. Use it like this time_ago('2014-12-03 16:25:26')
function time_ago($date){
$retval = NULL;
$granularity=2;
$date = strtotime($date);
$difference = time() - $date;
$periods = array('decade' => 315360000,
'year' => 31536000,
'month' => 2628000,
'week' => 604800,
'day' => 86400,
'hour' => 3600,
'minute' => 60,
'second' => 1);
foreach ($periods as $key => $value)
{
if ($difference >= $value)
{
$time = round($difference/$value);
$difference %= $value;
$retval .= ($retval ? ' ' : '').$time.' ';
$retval .= (($time > 1) ? $key.'s' : $key);
$granularity--;
}
if ($granularity == '0') { break; }
}
return $retval.' ago';
}
What you need to do is convert both dates to timestamp first and substract your original post date from current date and reconvert it back to your desired format. As an example see below.
$now = time();
$datePosted = strtotime($item['date']);
$timePassed = $now - $datePosted;
$agoMinutes = $timePassed/60; //this will give you how many minutes passed
$agoHours = $agoMinutes/60; //this will give you how many hours passed
$agoDays = $agoHours/24; // this will give you how many days passed
And so on ...
Php's timestamp gives date in seconds so it is easier to calculate and work on it if you need mathematical operations.

Convert Standard Date to Current Time in Hours/Mins/

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

Categories