Today is December 21, 2005. To me, 2 years, 2 months ago was October 21, 2003.
It took a while to write. The first version used brute force to get the difference out of mktime. That worked perfectly but was slow. I used it to generate a bunch of test cases, though.
What I eventually figured out is that you can just subtract the beginning years, months, hours, etc. from the current ones. After that, use borrowing similar to long subtraction to get rid of any negative numbers. Seconds borrow 60 from a minute, hours borrow 24 from a day, days borrow from an array of month lengths. You get the idea. Anyway, here’s the code, which I’ll post on the SmartyPlugins wiki as soon as I figure out how.
<?php
/**
* Smarty plugin
* -----------------------------------------
* File: modifier.human_age.php
* Type: modifier
* Name: human_age
* Params: from_time unix timestamp (required)
* to_time unix timestamp (default=false (means now))
* strip_zeroes remove units with zero values ("0 days") (default=true)
* limit limit the number of units returned (default=no limit)
* Author: Michael Barton (http://www.weirdlooking.com/email)
* Purpose: Returns a human-readable difference between two times
* e.g. "1 day, 8 hours, 48 minutes, 57 seconds"
* Remarks: Correct for leap years and different-sized months.
* Well, my idea of correct. Turns out it's slightly subjective.
*
* @link http://www.weirdlooking.com/blog/45
* -----------------------------------------
*/
require_once $smarty->_get_plugin_filepath('shared','make_timestamp');
function smarty_modifier_human_age($from_time, $to_time = false, $strip_zeroes = true, $limit = false)
{
if ($to_time === false)
$to_time = time();
$order = array('year', 'mon', 'mday', 'hours', 'minutes', 'seconds');
$names = array('year', 'month', 'week', 'day', 'hour', 'minute', 'second');
$sizes = array(12, 2=>24, 60, 60);
$month_lengths = array(31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30);
$from = getdate($from_time);
$to = getdate($to_time);
$delta = array();
foreach ($order as $unit)
$delta[] = $to[$unit] - $from[$unit];
for ($i = 5; $i >= 0; $i--)
if ($delta[$i] < 0)
{
$delta[$i-1]--;
if ($i == 2 && ($to['mon'] == 3 && !($to['year'] % 4)))
$delta[$i] += 29; // fix this before the year 2100!!!
else if ($i == 2)
$delta[$i] += $month_lengths[$to['mon']-1];
else
$delta[$i] += $sizes[$i-1];
}
$delta[2] -= ($week = floor($delta[2]/7)) * 7;
$delta = array($delta[0], $delta[1], $week, $delta[2], $delta[3], $delta[4], $delta[5]);
$ret = array();
foreach ($delta as $i => $val)
if (($delta[$i] || !$strip_zeroes) && ($limit === false || sizeof($ret) < $limit))
$ret[] = $delta[$i].' '.$names[$i].($delta[$i] == 1 ? '' : 's');
return join(', ', $ret);
}
?>

Thanks