PHP time conversion - php

Is there a PHP library that will convert a unix timestamp into something like this format:
8 hours and 17 minutes ago
I made my own script a while back that did this, I just can't track it down and would rather not spend the time recreating it (plus I think it could have been done far more efficiently).
My original code was something along the lines of:
$seconds = time() - $timestamp;
$minutes = 0;
$hours = 0;
$days = 0;
$weeks = 0;
$months = 0;
$years = 0;
while($seconds >= 60)
{
$seconds -= 60;
$minutes ++;
if($minutes >= 60)
{
$minutes -= 60;
$hours ++;
if($hours >= 24)
{
// etc
}
}
}
if($hours < 1) return "$minutes minute" . ($minutes == 1 ? "" : "s")) . " and $seconds seconds" . ($seconds == 1 ? "" : "s"));
if($minutes < 1) return "$seconds second" . ($seconds == 1 ? "" : "s"));
// etc
Better yet, if there's a nicer way to approach the above I'll give it a crack myself as well.

Yes, check The DateTime class.
$datetime1= new DateTime();
$datetime2= new DateTime();
$datetime2->setTimestamp($timestamp);
$interval = $datetime2->diff($datetime1);
echo $interval->format('%a days %h hours and %i minutes ago');

function TimeAgo($datefrom,$dateto=-1)
{
// Defaults and assume if 0 is passed in that
// its an error rather than the epoch
if($datefrom<=0) { return "A long time ago"; }
if($dateto==-1) { $dateto = time(); }
// Calculate the difference in seconds betweeen
// the two timestamps
$difference = $dateto - $datefrom;
// If difference is less than 60 seconds,
// seconds is a good interval of choice
if($difference < 60)
{
$interval = "s";
}
// If difference is between 60 seconds and
// 60 minutes, minutes is a good interval
elseif($difference >= 60 && $difference<60*60)
{
$interval = "n";
}
// If difference is between 1 hour and 24 hours
// hours is a good interval
elseif($difference >= 60*60 && $difference<60*60*24)
{
$interval = "h";
}
// If difference is between 1 day and 7 days
// days is a good interval
elseif($difference >= 60*60*24 && $difference<60*60*24*7)
{
$interval = "d";
}
// If difference is between 1 week and 30 days
// weeks is a good interval
elseif($difference >= 60*60*24*7 && $difference <
60*60*24*30)
{
$interval = "ww";
}
// If difference is between 30 days and 365 days
// months is a good interval, again, the same thing
// applies, if the 29th February happens to exist
// between your 2 dates, the function will return
// the 'incorrect' value for a day
elseif($difference >= 60*60*24*30 && $difference <
60*60*24*365)
{
$interval = "m";
}
// If difference is greater than or equal to 365
// days, return year. This will be incorrect if
// for example, you call the function on the 28th April
// 2008 passing in 29th April 2007. It will return
// 1 year ago when in actual fact (yawn!) not quite
// a year has gone by
elseif($difference >= 60*60*24*365)
{
$interval = "y";
}
// Based on the interval, determine the
// number of units between the two dates
// From this point on, you would be hard
// pushed telling the difference between
// this function and DateDiff. If the $datediff
// returned is 1, be sure to return the singular
// of the unit, e.g. 'day' rather 'days'
switch($interval)
{
case "m":
$months_difference = floor($difference / 60 / 60 / 24 /
29);
while (mktime(date("H", $datefrom), date("i", $datefrom),
date("s", $datefrom), date("n", $datefrom)+($months_difference),
date("j", $dateto), date("Y", $datefrom)) < $dateto)
{
$months_difference++;
}
$datediff = $months_difference;
// We need this in here because it is possible
// to have an 'm' interval and a months
// difference of 12 because we are using 29 days
// in a month
if($datediff==12)
{
$datediff--;
}
$res = ($datediff==1) ? "$datediff month ago" : "$datediff
months ago";
break;
case "y":
$datediff = floor($difference / 60 / 60 / 24 / 365);
$res = ($datediff==1) ? "$datediff year ago" : "$datediff
years ago";
break;
case "d":
$datediff = floor($difference / 60 / 60 / 24);
$res = ($datediff==1) ? "$datediff day ago" : "$datediff
days ago";
break;
case "ww":
$datediff = floor($difference / 60 / 60 / 24 / 7);
$res = ($datediff==1) ? "$datediff week ago" : "$datediff
weeks ago";
break;
case "h":
$datediff = floor($difference / 60 / 60);
$res = ($datediff==1) ? "$datediff hour ago" : "$datediff
hours ago";
break;
case "n":
$datediff = floor($difference / 60);
$res = ($datediff==1) ? "$datediff minute ago" :
"$datediff minutes ago";
break;
case "s":
$datediff = $difference;
$res = ($datediff==1) ? "$datediff second ago" :
"$datediff seconds ago";
break;
}
return $res;
}

/*
Input parameter is the UNIX timestamp
of the starting date.
The second parameter is optional -
It's value is the ending date,
also UNIX timestamp. If this
parameter is not given, the
default date is current date.
*/
function duration($start,$end=null) {
$end = is_null($end) ? time() : $end;
$seconds = $end - $start;
$days = floor($seconds/60/60/24);
$hours = $seconds/60/60%24;
$mins = $seconds/60%60;
$secs = $seconds%60;
$duration='';
if($days>0) $duration .= "$days days ";
if($hours>0) $duration .= "$hours hours ";
if($mins>0) $duration .= "$mins minutes ";
if($secs>0) $duration .= "$secs seconds ";
//$duration = trim($duration);
if($duration=='') $duration = '0 seconds';
return $duration;
}
It it not suits you better use some classes, given below
http://www.phpclasses.org/browse/file/6330.html

Related

PHP timestamp hours to days

I have a timestamp which I need to return as:
When it's under 1 hour I need it to say "30 minutes ago".
When it's under 24 hours I need it to say "6 hours ago".
When it gets to 24 hours I need it to say "1 day ago".
When it gets to 48 hours I need it to say "2 days ago".
Would this be done with a conditional statement?
So far I can return the number of days:
$post_timestamp = strtotime($post_timestamp);
$current_date = strtotime(time());
$datediff = $current_date - $post_timestamp;
$days = floor($datediff/(60*60*24));
I guess you can use DateTime, DateInterval and DatePeriod:
$date1 = new DateTime();
$date2 = DateTime::createFromFormat('U', $post_timestamp); # I assume a unix timestamp here
//determine what interval should be used - 1 minute
$interval = new \DateInterval('PT1M');
//create periods every minute between the two dates
$periods = new \DatePeriod($date2, $interval, $date1);
//count the number of objects within the periods
$mins = iterator_count($periods);
if ($mins < 60)
{
$say = "30 minutes ago";
} elseif ( $mins >= 60 and $mins < 60 * 24)
{
$say = "6 hours ago";
} elseif ( $mins >= 60 * 24 and $mins < 60 * 48)
{
$say = "1 day ago";
} elseif ( $mins >= 60 * 48)
{
$say = "2 days ago";
}
print $say;
You can use code like following :
date_default_timezone_set('Asia/Calcutta');
$post_timestamp="2017-05-21 5:00 pm";
$post_timestamp = strtotime($post_timestamp);
$current_date = strtotime(date('Y-m-d h:i a'));
$datediff = $current_date - $post_timestamp;
$mins = ($datediff) / 60;
$hours = $datediff / ( 60 * 60 );
You will get minutes and hours using this, put your condition accordingly

PHP time elapsed, remove "and" before seconds

So, I've got this working code which converts a MySQL date to UNIX Timestamp and subtracts it from the current date() to show a "time elapsed since X"-like timer. (the part which takes the date from database is missing since it's in another script)
<?php
function time_elapsed($secs){
$bit = array(
' year' => $secs / 31556926 % 12,
' week' => $secs / 604800 % 52,
' day' => $secs / 86400 % 7,
' hour' => $secs / 3600 % 24,
' minute' => $secs / 60 % 60,
' second' => $secs % 60
);
foreach($bit as $k => $v){
if($v > 1)$ret[] = $v . $k . 's';
if($v == 1)$ret[] = $v . $k;
}
array_splice($ret, count($ret)-1, 0, 'and');
$ret[] = 'ago.';
return join(' ', $ret);
}
$nowtime = time() + 10; //add 10s to avoid error
$oldtime = strtotime($mysqltime2);
$time_elapsed = time_elapsed($nowtime-$oldtime)."\n";
echo wordwrap($time_elapsed,35,"<br />\n"); //split long line
?>
I managed to fix an error reporting missing array or something if the script was executed at the same time of the MySQL date by adding 10 seconds to the current timestamp.
Another issue I have is that the script shows "and X seconds" even if there aren't minutes/hours/days/etc before it.
E.g.
"and X seconds"
"Y minutes and X seconds"
"Z hours Y minutes and X seconds"
"N days Z hours Y minutes and X seconds"
I want to remove the "and" before seconds ONLY if there's no minutes/hours/etc before it.
Any tip on how to fix this?
You could only splice when needed:
if( count($ret) > 1 ) {
array_splice($ret, count($ret)-1, 0, 'and');
}
Not sure if this will help, but why not do most of the date maths in mysql?
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html
Here is something I did before to list posts in a comments section of a site, it outputs "post made 2 hours ago" etc
SQL:
UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(made_on) as madeon
PHP (pass madeon from query to here):
function seconds_to_textual_time_ago($seconds)
{
$hour = 60* 60;
$day = 24 * $hour;
$month = 30 * $day;
$year = 365 * $day;
switch(true)
{
case ($seconds < 60) :
$time_ago = "Less than 1 minute ago";
break;
case ($seconds >= 60 && $seconds < $hour):
$minutes = floor($seconds /60);
if ($minutes > 1)
$time_ago = "$minutes minutes ago";
else
$time_ago = "1 minute ago";
break;
case ($seconds >= $hour && $seconds < $day):
$hours = floor($seconds /$hour);
if ($hours > 1)
$time_ago = "$hours hours ago";
else
$time_ago = "1 hour ago";
break;
case ($seconds >= $day && $seconds < $month):
$days = floor($seconds /$day);
if ($days > 1)
$time_ago = "$days days ago";
else
$time_ago = "1 day ago";
break;
case ($seconds >= $month && $seconds < $year):
$months = floor($seconds /$month);
if ($months > 1)
$time_ago = "$months months ago";
else
$time_ago = "1 month ago";
break;
case ($seconds >= $year ):
$years = floor($seconds /$year);
if ($years > 1)
$time_ago = "$years years ago";
else
$time_ago = "1 year ago";
break;
default:
break;
}
return $time_ago;
}
The simplest I can think of is
$time_elapsed = time_elapsed($nowtime-$oldtime))."\n";
if($nowtime-$oldtime < 61){
$time_elapsed=str_replace('and ',' ',$time_elapsed);
}

Is there something built into PHP to convert seconds to days, hours, mins?

For example if I have:
$seconds = 3744000; // i want to output: 43 days, 8 hours, 0 minutes
Do I have to create a function to convert this? Or does PHP already have something built in to do this like date()?
function secondsToWords($seconds)
{
$ret = "";
/*** get the days ***/
$days = intval(intval($seconds) / (3600*24));
if($days> 0)
{
$ret .= "$days days ";
}
/*** get the hours ***/
$hours = (intval($seconds) / 3600) % 24;
if($hours > 0)
{
$ret .= "$hours hours ";
}
/*** get the minutes ***/
$minutes = (intval($seconds) / 60) % 60;
if($minutes > 0)
{
$ret .= "$minutes minutes ";
}
/*** get the seconds ***/
$seconds = intval($seconds) % 60;
if ($seconds > 0) {
$ret .= "$seconds seconds";
}
return $ret;
}
print secondsToWords(3744000);
This is very simple and easy to find days , hours, minute and second in core php :
$dbDate = strtotime("".$yourdbtime."");
$endDate = time();
$diff = $endDate - $dbDate;
$days = floor($diff/86400);
$hours = floor(($diff-$days*86400)/(60 * 60));
$min = floor(($diff-($days*86400+$hours*3600))/60);
$second = $diff - ($days*86400+$hours*3600+$min*60);
if($days > 0) echo $days." Days ago";
elseif($hours > 0) echo $hours." Hours ago";
elseif($min > 0) echo $min." Minutes ago";
else echo "Just now";
An easy way to accomplish this nowadays is using DateTimeImmutable, DateInterval and PHP 5.5.0 or higher:
$seconds = 3744000;
$interval = new DateInterval("PT{$seconds}S");
$now = new DateTimeImmutable('now', new DateTimeZone('utc'));
$difference = $now->diff($now->add($interval))->format('%a days, %h hours, %i minutes');
The result will be:
43 days, 8 hours, 0 minutes
The code adds the seconds to a date and calculates the difference to it. Like this, the seconds are transformed into the specified days, hours and minutes.
Warning 1: Working without UTC - Clock changes
You may not specify the DateTimeZone in the constructor of the DateTimeImmutable object to UTC.
$now = new DateTimeImmutable();
There are regions in this world, where the clock changes on specific days of the year. Most countries in the EU change between a summer- and winter-time for example.
If your date interval overlaps the day on that a clock change occurs and your server is set to the related region for that clock change, the result might change as well. This is best shown with the following example:
$twentyFourHours = new DateInterval('PT24H');
$twentyFiveHours = new DateInterval('PT25H');
//Pacific time changed from summer- to winter-time on that day
$summerToWinter = new DateTimeImmutable('2018-11-04');
If you add 24 hours to the $summerToWinter date, you will get the following result:
$extra24Hours = $summerToWinter->add($twentyFourHours);
echo $summerToWinter->format('y-m-d H:i');
echo $extra24Hours->format('y-m-d H:i');
echo $summerToWinter->diff($extra24Hours)->format('%a days, %h hours, %i minutes');
18-11-04 00:00
18-11-04 23:00
0 days, 24 hours, 0 minutes
As you can see, between 00:00 and 23:00 on that day lay 24 hours, which is technically correct. Because of the clock change the timelap between 02:00 and 03:00 occured twice on that day.
Adding 25 hours will result in this:
$extra25Hours = $summerToWinter->add($twentyFiveHours);
echo $summerToWinter->format('y-m-d H:i');
echo $extra25Hours->format('y-m-d H:i');
echo $summerToWinter->diff($extra25Hours)->format('%a days, %h hours, %i minutes');
18-11-04 00:00
18-11-05 00:00
1 days, 0 hours, 0 minutes
As we can see, 1 day elapsed, that has had 25 hours. If this is applied for the 3744000 seconds from the original question, the result would show:
43 days, 7 hours, 0 minutes
The information, that an elapsed day has had 25 hours, is not shown though.
Also, I was not able to recreate the same effect for a day that changes the clock from winter to summer time, that should only elapse 23 hours.
Warning 2: Working with the raw DateInterval object
Using this code without DateTimeImmutable will cause the wrong output:
$seconds = 3744000;
$interval = new DateInterval("PT{$seconds}S");
$difference = $interval->format('%a days, %h hours, %i minutes, %s seconds');
Now, only the seconds are set in the DateInterval object. $difference would be:
(unknown) days, 0 hours, 0 minutes, 3744000 seconds
I like Ian Gregory's answer the most and upvoted it but thought i'd just simplify it a little bit :
function secondsToWords($seconds)
{
$days = intval(intval($seconds) / (3600*24));
$hours = (intval($seconds) / 3600) % 24;
$minutes = (intval($seconds) / 60) % 60;
$seconds = intval($seconds) % 60;
$days = $days ? $days . ' days' : '';
$hours = $hours ? $hours . ' hours' : '';
$minutes = $minutes ? $minutes . ' minutes' : '';
$seconds = $seconds ? $seconds . ' seconds' : '';
return $days . $hours . $minutes . $seconds;
}

How to calculate the difference between two days as a formatted string?

Here's what I've got so far:
/**
* Parse a duration between 2 date/times in seconds
* and to convert that duration into a formatted string
*
* #param integer $time_start start time in seconds
* #param integer $time_end end time in seconds
* #param string $format like the php strftime formatting uses %y %m %w %d %h or %i.
* #param boolean $chop chop off sections that have 0 values
*/
public static function FormatDateDiff($time_start = 0, $time_end = 0, $format = "%s", $chop = false) {
if($time_start > $time_end) list($time_start, $time_end) = array($time_end, $time_start);
list($year_start,$month_start,$day_start) = explode('-',date('Y-m-d',$time_start));
list($year_end,$month_end,$day_end) = explode('-',date('Y-m-d',$time_end));
$years = $year_end - $year_start;
$months = $month_end - $month_start;
$days = $day_start - $day_end;
$weeks = 0;
$hours = 0;
$mins = 0;
$secs = 0;
if(mktime(0,0,0,$month_end,$day_end) < mktime(0,0,0,$month_start,$day_start)) {
$years -= 1;
}
if($days < 0) {
$months -= 1;
$days += 30; // this is an approximation...not sure how to figure this out
}
if($months < 0) $months += 12;
if(strpos($format, '%y')===false) {
$months += $years * 12;
}
if(strpos($format, '%w')!==false) {
$weeks = floor($days/7);
$days %= 7;
}
echo date('Y-m-d',$time_start).' to '.date('Y-m-d',$time_end).": {$years}y {$months}m {$weeks}w {$days}d<br/>";
}
(It's incomplete and inaccurate)
I can't seem to get the math right. Naively dividing it out won't work because of leap years and differing lengths of months.
The logic also needs to change depending on the format string. For example, passing 04-Feb-2010 to 28-Jun-2011 (as unix timestamps) with format string %y year %m month %d day should output 1 year 4 month 24 day but if %y year is omitted then it needs to add 12 months to the month, i.e., output should be 16 month 24 day.
Should handle times too...but I haven't got to that yet.
None of these date_diff solutions handle weeks. And I don't know how I could hack it into date_diff, so that's not really a solution for me.
Furthermore, $diff->format doesn't do what I asked...to give the total months and days if "bigger units" are omitted. Example:
>>> $start = new DateTime('04-Feb-2010')
>>> $end = new DateTime('28-Jun-2011')
>>> $diff = $start->diff($end)
>>> $diff->format('%m months, %d days')
'4 months, 24 days'
Should be 16 months, 24 days, as I stated earlier. Please stop being so quick to close my question as a dupe before you understand it fully. If the solutions to other questions can be tweaked to solve this, fine, but please explain how, because I don't get it.
To be clear,
if %y is omitted, years should be rolled in the months
if %m is omitted, months should be rolled into the days
if %w is omitted, weeks should be rolled into the days
if %h is omitted, hours should be rolled into minutes
if %m is omitted, minutes should be rolled into seconds
If "smaller units" are omitted, the next biggest unit can be rounded or floored where it makes sense.
I don't expect an accepted answer, but here is how to get date_diff to do weeks.
<?php
$january = new DateTime('2010-01-01');
$february = new DateTime('2011-02-20 3:35:28');
$interval = $february->diff($january);
$parts = $interval->format('%y %m %d %h %i %s %a');
$weeks = 0;
list($years, $months, $days, $hours, $minutes, $seconds, $total_days) = explode(' ', $parts);
if ($days >= 7) {
$weeks = (int)($days / 7);
$days %= 7;
}
echo "$years years, $months months, $weeks weeks, $days days, $hours hours, $minutes minutes $seconds seconds";
// 1 years, 1 months, 2 weeks, 5 days, 3 hours, 35 minutes 28 seconds
Maybe with that you can integrate it into your function to do the rolling over and handling the user given format.
If the bigger units aren't given, you can start from the largest unit and apply them back to the next smaller unit. (i.e. 1 year 1 month with no years should add 12 back to months). If "month" isn't included in the format, then you can use the total days to handle the fact that months have different numbers of days.
I would use DateTime::diff() for this:
$start = new DateTime('2012-01-01 12:00:00');
$end = new DateTime('2012-01-20 06:59:59');
$diff = $start->diff($end);
echo $diff->format('%d days, %h hours, %m minutes, %s seconds');
See DateInterval::format() for more info about the formats.
$absolute = false; //default, returns years, months, days, etc. True would return seconds
$difference = date_diff($dateTimeStart, $dateTimeEnd, $absolute);
echo $difference->format("%y Year(s) %m Month(s) ...");
I would try this first, if it does not work for your purposes then you could try to use the Calendar functions to fetch the correct number of days in each month.
I think you would need to decide upon your own logic for calculating weeks. Personally, I would say $weeks = $difference->d / 7; but there is no strictly correct way to count elapsed weeks in a portion of a month. Think of a calendar, we often speak of first, second, third week, but unless the month started on a Sunday (or Monday, or Saturday, depending on company, religion, etc.) then really we are not being absolute in these descriptions. You can say absolutely that there have been 3 Sundays (for instance) since the beginning of the month, but not three weeks. On the 28th, have four weeks passed? What if the month started on Wed, then is it five?
Also, if you want a custom format (35 Months) you can always access the members directly and concatenate a format string.
Here's my attempt at an interesting problem. It's not quite working 100%, but it's very close.
The function begins by calculating the total number of seconds and months that the date difference requires. Then, using the $tokens array that is sorted in ascending order, it loops through those tokens and tries to match it with the input $format. If the $format is found, the appropriate value is subtracted from the total number of months or seconds.
However, there is a possibility of having a value greater than zero for months or years, but the $format string didn't specify either of those parameters. If so, the function rolls over the appropriate number of days in order to come up with the correct calculations.
I've briefly tested it, and it works for all of the examples in this thread. You can test it out on codepad to see if you can break it! :) I'd be interested in improvements upon this.
<?php
function calc( $start, $end, $format = '%s', $chop = false)
{
$tokens = array( '%y', '%m', '%w', '%d', '%h', '%i', '%s');
if( !is_a( $start, 'DateTime') || !is_a( $end, 'DateTime'))
{
return;
}
$diff = $start->diff( $end);
$months = ($diff->y * 12) + $diff->m;
$secs = ($diff->d * 24 * 3600) +
($diff->h * 3600) +
($diff->i * 60) +
($diff->s);
$output = array();
while( $token = array_shift( $tokens))
{
$token_present = !(strpos( $format, $token) === false);
switch( $token)
{
case '%y':
if( ($months / 12) > 0 && $token_present)
{
$output[$token] = floor( $months / 12);
$months -= $output[$token] * 12;
}
break;
case '%m':
if( $months > 0 && $token_present)
{
$output[$token] = $months;
$months = 0;
}
break;
case '%w':
// Rollover between (months or years) and seconds
if( (!isset( $output['%y']) || !isset( $output['%m'])) && $months > 0)
{
$days = $diff->format( '%a');
// Need a fix for leap year probably.
$days -= (isset( $output['%y'])) ? ($output['%y'] * 365) : 0;
$days -= $diff->d;
$secs += ($days * 24 * 60 * 60);
}
$val = (7 * 24 * 60 * 60);
if( ($secs / $val) > 0 && $token_present)
{
$output[$token] = floor( $secs / $val);
$secs -= $output[$token] * $val;
}
break;
case '%d':
$val = (24 * 60 * 60);
if( ($secs / $val) > 0 && $token_present)
{
$output[$token] = floor( $secs / $val);
$secs -= $output[$token] * $val;
}
break;
case '%h':
$val = (60 * 60);
if( ($secs / $val) > 0 && $token_present)
{
$output[$token] = floor( $secs / $val);
$secs -= $output[$token] * $val;
}
break;
case '%i':
$val = (60);
if( ($secs / $val) > 0 && $token_present)
{
$output[$token] = floor( $secs / $val);
$secs -= $output[$token] * $val;
}
break;
case '%s':
if( $secs > 0 && $token_present)
{
$output[$token] = $secs;
}
break;
}
}
// Filter out blank keys and replace their tokens in the $format string
$filtered = $chop ? array_filter( $output) : $output;
$format = str_replace( array_diff( array_keys($output), array_keys($filtered)), '', $format);
return str_replace( array_keys( $filtered), array_values( $filtered), $format);
}
$start = new DateTime('04-Feb-2010');
$end = new DateTime('28-Jun-2011');
echo calc( $start, $end, "%m months %d days\n"); // 16 months 24 days
$january = new DateTime('2010-01-01');
$february = new DateTime('2011-02-20 3:35:28');
echo calc( $january, $february, '%y years %m months %w weeks %d days %h hours %i minutes %s seconds'); // 1 years 1 months 2 weeks 5 days 3 hours 35 minutes 28 seconds
I think I've got it:
if($time_start > $time_end) list($time_start, $time_end) = array($time_end, $time_start);
$start_dt = new DateTime();
$end_dt = new DateTime();
$start_dt->setTimestamp($time_start);
$end_dt->setTimestamp($time_end);
$has_time = preg_match('`%[his]`',$format) > 0;
if(!$has_time) {
$start_dt->setTime(0,0,0);
$end_dt->setTime(0,0,0);
}
$interval = $end_dt->diff($start_dt);
$parts = $interval->format('%y %m %d %h %i %s %a');
$weeks = 0;
list($years, $months, $days, $hours, $mins, $secs, $total_days) = explode(' ',$parts);
if(strpos($format,'%y')===false) {
$months += $years * 12;
}
if(strpos($format,'%m')===false) {
$days = $total_days;
if(strpos($format,'%y')!==false) {
$start_dt->add(new DateInterval('P'.$years.'Y'));
$interval = $end_dt->diff($start_dt);
$days = $interval->days;
}
}
if(strpos($format,'%w')!==false) {
$weeks = (int)($days/7);
$days %= 7;
}
if(strpos($format,'%d')===false) {
$hours += $days * 24;
}
if(strpos($format,'%h')===false) {
$mins += $hours * 60;
}
if(strpos($format,'%i')===false) {
$secs += $mins * 60;
}
(FYI, I just do some basic str_replacing at the end to throw it into my custom format string)
Edit: There's still 1 more scenario I don't know how to handle... when years and days are requested but not months, the output will be wrong. I'm wondering if I should just mod the total days with 365.... it's kind of a rare scenario.
Edit2: Solved it! We'll just add that many years to the start date and then recalculate the total days.

Use PHP to truncate the age of a MySQL entry to the nearest unit of time

I have a table with a datetime field, and I want to pull that time stamp and use PHP to convert it to the nearest largest unit of time. For example, if the entry was made 2 minutes and 36 seconds ago, I want to echo 2 minutes in PHP. If it was 3 hours and 5 minutes ago, I want it to say 3 hours. If it was 6 days and 4 hours and 40 minutes ago, it should say 6 days. You get my drift. And if it's under a minute, just the number of seconds.
I am not familiar at all about any of PHP's date or time functions, so please don't assume I already know anything. Thanks.
Here's another function for you:
function relativeTime($timestamp, $format = "Y-m-d")
{
$difference = time() - $timestamp;
if ($difference >= 604800) { // 7 days
return date($format, $timestamp);
}
$periods = array("Second", "Minute", "Hour", "Day");
$lengths = array("60","60","24","7","4.35","12","10");
$ending = "Ago";
for($j = 0; $difference >= $lengths[$j]; $j++)
$difference /= $lengths[$j];
$difference = round($difference);
if($difference != 1) $periods[$j].= "s";
$text = "$difference $periods[$j] $ending";
return $text;
}
It returns values like "5 Minutes Ago", "3 Days Ago", and "34 Seconds Ago". However if the date is over 7 days old, it just returns the full date, i.e. "2010-04-19".
If your field is date or datetime use
SELECT UNIX_TIMESTAMP(field) FROM...
if your field is stored as an int (seconds since 1970) just use
SELECT field FROM...
Get that integer value from the database into a PHP variable $secs, this is the number of seconds since 1970. We assume the date is in the past, then
$diff = time() - $secs;
if ($diff < 60) echo $diff . ' seconds';
else {
$diff = intval($diff / 60);
if ($diff < 60) echo $diff . ' minutes';
else {
$diff = intval($diff / 60);
if ($diff < 24) echo $diff . ' hours';
else {
$diff = intval($diff / 24);
echo $diff . ' days';
}
}
}

Categories