2

I have the following timestamp 1347216222 which is of day and am using it with a time_since function to check how long ago it was in hours.. minutes etc.

<?php

/* Works out the time since the entry post, takes a an argument in unix time (seconds) */
function time_since($original) {
    // array of time period chunks
    $chunks = array(
        array(60 * 60 * 24 * 365 , 'year'),
        array(60 * 60 * 24 * 30 , 'month'),
        array(60 * 60 * 24 * 7, 'week'),
        array(60 * 60 * 24 , 'day'),
        array(60 * 60 , 'hour'),
        array(60 , 'minute'),
    );

    $today = time(); /* Current unix time  */
    $since = $today - $original;

    // $j saves performing the count function each time around the loop
    for ($i = 0, $j = count($chunks); $i < $j; $i++) {

        $seconds = $chunks[$i][0];
        $name = $chunks[$i][1];

        // finding the biggest chunk (if the chunk fits, break)
        if (($count = floor($since / $seconds)) != 0) {
            // DEBUG print "<!-- It's $name -->\n";
            break;
        }
    }

    $print = ($count == 1) ? '1 '.$name : "$count {$name}s";

    if ($i + 1 < $j) {
        // now getting the second item
        $seconds2 = $chunks[$i + 1][0];
        $name2 = $chunks[$i + 1][1];

        // add second item if it's greater than 0
        if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0) {
            $print .= ($count2 == 1) ? ', 1 '.$name2 : ", $count2 {$name2}s";
        }
    }
    return $print;
}

echo time_since(1347216222);

?>

The output is -1 years, 12 months. Can anyone help me to fix this?

Herbert
  • 5,698
  • 2
  • 26
  • 34
Jake
  • 3,326
  • 7
  • 39
  • 59
  • 1
    Look at this question: http://stackoverflow.com/questions/5010016/php-time-since-function –  Sep 09 '12 at 11:02
  • 5
    I answered such a question 2 times yesterday... – Alain Tiemblo Sep 09 '12 at 11:04
  • Look at this answer: http://stackoverflow.com/a/5010169/911182 – Herbert Sep 09 '12 at 11:14
  • I've just noticed that the time() in php and the default timestamp in the database are different timezones... – Jake Sep 09 '12 at 11:18
  • 1
    This is why I encourage people to use `DateTime`, `DateInterval`, and `DateTimeZone` unless you absolutely MUST support PHP < 5.3. See http://www.php.net/manual/en/book.datetime.php – Herbert Sep 09 '12 at 11:24

1 Answers1

0

I tailored the function to use DateTime and DateInterval, which makes it more readable.

It differs from the function you posted with regard to how the time difference is treated. In your case, you tested the values twice (once for each "unit"). This required complex calculations on your part.

The function below, on the other hand, takes advantage of the fact that DateInterval gives you a ready-to-use difference in years, moths, days, hours, minutes and seconds (e.g. the difference between 2015 and 2014 is 1 year and 0 seconds, as opposed to UNIX timestamps). Furthermore, the usage of DateTime allows you to handle timezones gracefully.

That being said, all you need to care of is how to print that difference, and this is exactly what the for loops are for - we extract two values and use an extra item (we call such items guardians), to save additional conditions when we want to extract the second item.

Here's the function:

<?php
function pluralize($number, $unit) {
    return $number . ' ' . $unit . ($number !== 1 ? 's' : '');
}

function time_since(DateTime $original) {
    $now = new DateTime('now');
    $diff = $now->diff($original);

    //is from the past?
    if ($diff->invert) {
        $chunks = [
            [$diff->y, 'year'],
            [$diff->m, 'month'],
            [$diff->d, 'day'],
            [$diff->h, 'hour'],
            [$diff->i, 'minute'],
            [$diff->s, 'second'],
            [0, 'guardian'],
        ];

        for ($i = 0; $i < count($chunks) - 1; $i ++) {
            list ($value, $unit) = $chunks[$i];
            if ($value !== 0) {
                $text = pluralize($value, $unit);

                //append next unit as well, if it's available and nonzero
                list ($nextValue, $nextUnit) = $chunks[$i + 1];
                if ($nextValue !== 0) {
                    $text .= ' ' . pluralize($nextValue, $nextUnit);
                }

                return $text;
            }
        }
    }

    return 'just now';
}

And the tests:

echo time_since(new DateTime('2014-01-01')) . PHP_EOL;
echo time_since(new DateTime('2014-10-09')) . PHP_EOL;
echo time_since(new DateTime('2014-11-09')) . PHP_EOL;
echo time_since(new DateTime('2014-11-10')) . PHP_EOL;
echo time_since(new DateTime('2014-11-10 13:05')) . PHP_EOL;
echo time_since(new DateTime('2114-11-10 13:05')) . PHP_EOL; //future

Results:

rr-@work:~$ php test.php
10 months 9 days
1 month 1 day
1 day 13 hours
13 hours 5 minutes
38 seconds
just now
rr-
  • 14,303
  • 6
  • 45
  • 67