Welcome Guest, Not a member yet? Register   Sign In
date helper : date_when() - get time elapsed/to go
#1

[eluser]ntheorist[/eluser]
I was looking for a helper function to give me a date span in natural english, ie '3 days ago', '2 months from now' etc, but i decided just to write one and add it to CI's date helper. It's working pretty well for me so I thought i'd share it. It uses the date_helper now() function so its best to add it to the helper file.

it takes 1 argment, a unix timestamp, with an optional 2nd option to specify a different 'now' time:

Code:
$time = now() - 4*24*3600;
echo date_when($time); // Returns '4 days ago';

$time = now() - 1*24*3600;
echo date_when($time); // Returns 'Yesterday, 4:46pm' (or whenever the time was)

// Can do future times
$time = now() + 80*24*3600;
echo date_when($time); // Returns '2 Months from now'

// Using datetime value ie MySQL
echo date_when(human_to_unix($db_value));

// Using base date, ie Timezone change. Sort of redundant since now() does this
$actual_time = now() + 3600;
echo date_when($time, $actual_time);

Here it is:

Code:
if ( ! function_exists('date_when') )
{
    function date_when( $timestamp = NULL, $base = NULL)
    {
        if( strlen($timestamp) < 10 ) return;
        
        if( empty($base) ) $base = now();
        
        // Is timestamp in past or future?
        $past = ($base > $timestamp) ? TRUE : FALSE;
        
        // Create suffix based on past/future
        $suffix = $end = ($past) ? ' ago' : ' from now';
        
        // Actual time string of timestamp ie 4:54 pm
        $timestr = date('g:i a',$timestamp);
        
        $diff = abs($timestamp - $base);
        
        $periods = array('year'=>31536000,'month'=>2628000,'day'=>86400,'hour'=>3600,'minute'=>60,'second'=>1);
        
        // create array holding count of each period
        
        $out = array();
        
        foreach($periods as $period => $seconds)
        {
            if( $diff > $seconds )
            {
                $result = floor($diff/$seconds);
                $diff =  $diff % $seconds;
                $out[] = array($period, $result);
            }
        }
        
        // Get largest period, other counts are still in $out for use
        $top = array_shift($out);
        
        switch($top[0])
        {
            case 'month' :
                $output = $top[1] == 1 ? ( $past ? 'last month' : 'next month' ) : $top[1] . ' months' . $suffix;
                break;
            case 'day' :
                $output = $top[1] == 1 ? ( $past ? 'yesterday' : 'tomorrow' ) .', '. $timestr : $top[1] . ' days' . $suffix;
                break;
            case 'hour':
                // Calculate in case, for example if yesterday was only 7 hours ago
                $output = date('j',$base) == date('j',$timestamp) ? 'today, '.$timestr : (( $past ? 'yesterday' : 'tomorrow' ) . ', '.$timestr);
                break;
            default :
                $output = $top[1] .' '. $top[0] . ( $top[1] > 1 ? 's' : '' ) . $suffix;
                break;
        }
        
        
        return ucfirst($output);
        
    }
}

It's not 100% accurate. As with most date stuff it could be improved to include exact number of seconds in current month, account for leap years etc. But since it returns only the highest span of time, only in very narrow circumstances it would output, for instance 'Last Month' where it should output '2 months ago', etc.

cheers,

_CC
#2

[eluser]sophistry[/eluser]
nice work.

i like the clear, concise programming idiom. this is code by someone with a fair bit of experience!

i pored over it looking for holes, but besides the "known deficiencies" listed in the original post i couldn't find anything except for this:
Code:
$past = ($base > $timestamp) ? TRUE : FALSE;

could be tightened to:

Code:
$past = ($base > $timestamp);

cheers.

EDIT: found another minor glitch -
Code:
$suffix = $end = ($past) ? ' ago' : ' from now';

should be:
Code:
$suffix = ($past) ? ' ago' : ' from now';
#3

[eluser]Johan André[/eluser]
I did this a while ago. Uses the language-files too...
#4

[eluser]crmdesignstudio[/eluser]
Thanks for this, it's working great for me! The only issue I ran into was after adding a timestamped item, upon redirecting the user to the same page they added it from. After doing so, the relative time would just show " from now" since there is no case to handle when the timestamp is the same as the current time.

Just added...
Code:
// Set period to say '1 second ago' if you redirect user immediately after adding a timestamped item
if($base == $timestamp){
     $suffix = '1 second ago';
}

Cheers!
#5

[eluser]techgnome[/eluser]
crmdesign - you do know there is the timespan() function in the date_helper? It's right in the user's guide. http://ellislab.com/codeigniter/user-gui...elper.html

don't know how it handles the empty from now bit. But might want to look at it.

-tg
#6

[eluser]crmdesignstudio[/eluser]
Thanks techgnome, I did take a look at the timespan() function but I'm also using this to show how much time until an event in the future as well...which is where this helper came into play




Theme © iAndrew 2016 - Forum software by © MyBB