Format a time interval with the requested granularity

This class, a refactored version of Drupal’s format_interval function, makes it relatively easy to format an interval value. The format will automatically format as compactly as possible. For example: if the difference between the two dates is only a few hours and both dates occur on the same day, the year, month, and day parts of the date will be omitted.

class DateIntervalFormat
{
    /**
     * Format an interval value with the requested granularity.
     *
     * @param integer $timestamp The length of the interval in seconds.
     * @param integer $granularity How many different units to display in the string.
     * @return string A string representation of the interval.
     */
    public function getInterval($timestamp, $granularity = 2)
    {
        $seconds = time() - $timestamp;
        $units = array(
            '1 year|:count years' => 31536000,
            '1 week|:count weeks' => 604800,
            '1 day|:count days' => 86400,
            '1 hour|:count hours' => 3600,
            '1 min|:count min' => 60,
            '1 sec|:count sec' => 1);
        $output = '';
        foreach ($units as $key => $value) {
            $key = explode('|', $key);
            if ($seconds >= $value) {
                $count = floor($seconds / $value);
                $output .= ($output ? ' ' : '');
                if ($count == 1) {
                    $output .= $key[0];
                } else {
                    $output .= str_replace(':count', $count, $key[1]);
                }
                $seconds %= $value;
                $granularity--;
            }
            if ($granularity == 0) {
                break;
            }
        }

        return $output ? $output : '0 sec';
    }
}

Usage:

$dateFormat = new DateIntervalFormat();
$timestamp = strtotime('2009-06-21 20:46:11');
print sprintf('Submitted %s ago',  $dateFormat->getInterval($timestamp));

Outputs:

Submitted 3 days 4 hours ago
About these ads

9 thoughts on “Format a time interval with the requested granularity

  1. Cool. I wrote something similar to this a couple of weeks ago. The only differences being that the words for “day”, “month”, “year” etc were set as class properties so you could set externally and you could also set the date that you’re using as time() so you could measure betweek 2 specific dates if you wanted to.

    I’d like to implement something for MySQL timestamps as well – I don’t really trust unix ones.

  2. Pingback: Webs Developer

  3. Pingback: DreamNest

  4. You should do something with the explode(‘|’, $key) because it will done every time the function is called => If i call it 10 times the explode will be called 10 times per unit => 60 times! (perhaps hardcoded as a static array of class or function

    Also I would prefer the use of a static method, that would also speed the class up

    and last but not least i think i would prefer the strtotime-function inside of the getInterval-function so i don’t have to call it every time and save some annoying tipping ;)

  5. I really liked the idea you had, but for my purpose I had to change your class a bit. The first thing I changed was added support for PHP DateTime, including DateTimeZone so that the current date is compared correctly, I also changed the method so that a string with the current date can be passed (as Nzsz already mentioned).

    The second thing I changed was the support for leap years. Currently your class does not support those years and will generate an incorrect day/.. count for years < 2008.

    The other stuff is mostly for viewing pleasure, and to replace the names used.

    http://www.pastebin.be/19456

  6. Indeed, a year may contain one or more extra days. I guess for those who want more precision, then yes, it is important to take the leap year into consideration.

    Thanks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s