Click to See Complete Forum and Search --> : Relative Dates -- Revised!


rukuartic
09-04-2007, 04:06 PM
I wrote this for a small web app I was writing... I lost the previous one I had (which was sad... it had a neat thing where you could define the format...) but this one is more efficient, I think...

Anyone have a few ideas how to make it better?

<?

function reltime($old_time, $cur_time = -1)
{

// Code by RukuArtic, 2007

// Bunch of defines for my code...
define('YEAR', 1);
define('MONTH', 2);
define('WEEK', 3);
define('DAY', 4);
define('HOUR', 5);
define('MIN', 6);
define('SECOND', 7);

define('WORD_YEAR', " year");
define('WORD_MONTH', " month");
define('WORD_WEEK', " week");
define('WORD_DAY', " day");
define('WORD_HOUR', " hour");
define('WORD_MIN', " minute");
define('WORD_SEC', " second");

// This just makes pluralizing easier.
define('P', "s");

define('SEC_YEAR', 31556926);
define('SEC_MONTH', 2629744);
define('SEC_WEEK', 604800);
define('SEC_DAY', 86400);
define('SEC_HOUR', 3600);
define('SEC_MIN', 60);

$format = "%t ago";

// If they didn't set a time to compare it to, use the current time.
if($cur_time == -1)
$cur_time = time();

// Calculate the number of seconds between times, compensate for
// times in the future.
$diff = $cur_time - $old_time;
if($diff < 0)
{
$format = "in %t";
$diff = abs($diff);
}

// Heehee. This one's hard to get, but prevents "0 seconds ago"
if($diff == 0)
return "now";

// Calculate the number of years... etc, keep as integer.
// I'm sure this could be more efficient if we break as soon as we
// find a number that's not zero...
$num[YEAR] = (int)($diff / SEC_YEAR);
$diff = $diff % SEC_YEAR;
$num[MONTH] = (int)($diff / SEC_MONTH);
$diff = $diff % SEC_MONTH;
$num[WEEK] = (int)($diff / SEC_WEEK);
$diff = $diff % SEC_WEEK;
$num[DAY] = (int)($diff / SEC_DAY);
$diff = $diff % SEC_DAY;
$num[HOUR] = (int)($diff / SEC_HOUR);
$diff = $diff % SEC_HOUR;
$num[MINUTE] = (int)($diff / SEC_MIN);
$diff = $diff % SEC_MIN;
$num[SECOND] = $diff;

// Find the biggest value -- ie: 1 year > 11 months
$type = SECOND;
for($i = SECOND; $i >= YEAR; $i--)
if($num[$i] > 0)
$type = $i;

// Assume plural, unless the number is 1.
$plural = true;
if($num[$type] == 1)
$plural = false;

// And return it. If you don't know how this code works, read this article
// about the Ternary Operator (?:). http://en.wikipedia.org/wiki/%3F:
switch($type)
{
case YEAR:
return str_replace('%t', ($plural ? $num[YEAR] . WORD_YEAR . P : $num[YEAR] . WORD_YEAR), $format);
case MONTH:
return str_replace('%t', ($plural ? $num[MONTH] . WORD_MONTH . P : $num[MONTH] . WORD_MONTH), $format);
case WEEK:
return str_replace('%t', ($plural ? $num[WEEK] . WORD_WEEK . P : $num[WEEK] . WORD_WEEK), $format);
case DAY:
return str_replace('%t', ($plural ? $num[DAY] . WORD_DAY . P : $num[DAY] . WORD_DAY), $format);
case HOUR:
return str_replace('%t', ($plural ? $num[HOUR] . WORD_HOUR . P : $num[HOUR] . WORD_HOUR), $format);
case MINUTE:
return str_replace('%t', ($plural ? $num[MINUTE] . WORD_MINUTE . P : $num[MINUTE] . WORD_MINUTE), $format);
case SECOND:
return str_replace('%t', ($plural ? $num[SECOND] . WORD_SECOND . P : $num[SECOND] . WORD_SECOND), $format);
}
}
?>

NogDog
09-04-2007, 11:27 PM
Using a fixed number of seconds for the various intervals can be be problematic when there is a daylight saving time change between the dates or dealing with leap years.

You can see one alternative I developed for dealing with this at www.charles-reace.com/PHP_and_MySQL/Time_Difference/.

rukuartic
09-05-2007, 10:53 PM
I really like how you did that... it took me a moment to figure out how your code was working... But I'm not sure I like the concept of using strtotime for efficiency reasons. Yes it will handle leap years, but the purpose of this function was to give a general time period... EG: You received this email 5 minutes ago. The only error there might be is if an email was received the day before leap year, and the function was run the day of leap year. By the time things had blown out to weeks, there would be no noticeable difference.

Would strtotime be more efficient in this? I'd think it would increase execution time.

NogDog
09-06-2007, 01:21 AM
I'm fairly sure the strtotime() solution would be less efficient. But it seems to run pretty briskly. Worst case scenario would be something on the order of 200 loop iterations: x years + 12 months + 31 days + 24 hours + 60 minutes + 60 seconds.

It's a trade-off you'll have to choose depending on your specific needs of precision versus speed.

Weedpacket
09-07-2007, 05:10 AM
Why the constants?