tags:

views:

321

answers:

7

If my code looks like:

if($seconds < 60)
  $interval = "$seconds seconds ago";
else
 if($seconds < 3600)
     $interval = floor($seconds / 60) . "minutes ago";
else
    if($seconds < 86400)
         $interval = floor($seconds / 3600) . "hours ago";
    else
         $interval = floor($seconds / 86400) . "days ago";

How would I get rid of it saying stuff like:

1 Days ago. 1 Years ago. 1 Minutes ago. 1 Hours ago.

Thanks :)

A: 

Do the math.

else if($seconds < 120)
     $interval = "1 minute ago";
else if($seconds < 172800)
     $interval = "1 day ago"

etc.

Daniel A. White
+2  A: 
$time = "120";
$array = array("second" => 1,
               "minute" => 60,
      "hour" => 60,
      "day" => 24,
      "year" => 365);
$old_time = 0;
$old_type = false;

// Loop through each type
foreach($array as $type => $seconds)
{
 // Divide
 $time = floor($time/$seconds);
 // If it went into a value lower than 0, stop dividing
 if($time < 1)
 {
  $time = $old_time;
  $type = $old_type;
  break;
 }
 else
 {
  // Continue dividing.
  $old_time = $time;
  $old_type = $type;
 }
}
if($time == 1)
{
 $interval = $time . " ". $type . " ago";
}
else
{
 $interval = $time ." " . $type . "s ago";
}
echo $interval;

This divides through all the possible time types, and gives one that doesn't turn it into a fraction. By separating the number value from the type, we are then able to test if the number is == 1, and correct the word.

Chacha102
+1 Didn't think in this approach, very clever way!
Rodrigo
as long as you don't go international, yes. doesn't work in like all languages ;-)
Philippe Gerber
Just updated it with something a little different. Took awhile though.
Chacha102
But there has just got to be a library focused around relative time...
Chacha102
Just updated it something more expandable. You could do centuries very easily :)
Chacha102
+7  A: 

Can be done quite concisely with a ternary operator:

if($seconds < 60) {
    $interval = "$seconds second" . (($seconds != 1) ? "s" : "") . " ago";
} else {
    if($seconds < 3600) {
        $minutes = floor($seconds / 60);
        $interval = "$minutes minute" . (($minutes > 1) ? "s" : "") . " ago";
    } else {
        if($seconds < 86400) {
            $hours =  floor($seconds / 3600);
            $interval = "$hours hour" . (($hours > 1) ? "s" : "") . " ago";
        } else {
            $days = floor($seconds / 86400);
            $interval = "$days day" . (($days > 1) ? "s" : "") . " ago";
        }
    }
}
karim79
$interval = "$minutes " . (($minutes > 1) ? "minutes" : "minute") . " ago"; a little less repetition :-)
Philippe Gerber
@Philippe Gerber - Good call, go ahead and edit.
karim79
not enough karma ... :-)
Philippe Gerber
@Philippe Gerber - LOL@Karma - I wish SO called it that.
karim79
I applied your suggested edit, Phillipe, and made it even a bit shorter :)
Paul Fisher
And I even messed it up the first time. Silly me!
Paul Fisher
@Philippe go a step further: $interval = "$minutes minute" . (($minutes > 1) ? "s" : "") . " ago";
rezzif
@Paul Fisher - Nice one!, who says there's no team spirit on SO?
karim79
Just to be pedantic you could change it toabs($seconds) != 1 so that negative numbers would work.-1 second, -2 seconds :P
rezzif
+2  A: 

Yet another solution.

if($seconds < 60)
  $interval = "$seconds second";
 else
   if($seconds < 3600)
     $interval = floor($seconds / 60) . " minute";
   else
     if($seconds < 86400)
       $interval = floor($seconds / 3600) . " hour";
     else
       $interval = floor($seconds / 86400) . " day";
$interval .= (reset(explode(" ", $interval)) != 1 ? "s" : "")." ago";
danamlund
+1 - I love it!
karim79
+4  A: 

If your app is international and using the gettext extension, you can do something like this:

sprintf(ngettext('%d minute', '%d minutes', $amount), $amount);

You can create a wrapper function to it:

function pluralize($singular, $plural, $num) {
  return sprintf(ngettext($singular, $plural, $num), $num);
}

This is the best way imo.

orlandu63
+1  A: 
if ($interval < 60) {
    $unit = 'Second';
} else if ($interval < 1440) {
    $unit = 'Minute'; $interval /= 60;
} else if ($interval < 86400) {
    $unit = 'Hour'; $interval /= 1440;
} else {
    $unit = 'Day'; $interval /= 86400;
}
$interval = intval($interval);
$interval = "$interval  $unit" . ($interval == 1 ? '' : 's') . " ago";
Lucky
A: 

Here is a generic PHP snip for getting strings like "1 month, 2 weeks and 30 seconds ago".

$timeUnits = array("month" => 2592000,
                  "week" => 604800,
                  "day" => 86400,
                  "hour" => 3600,
                  "minute" => 60,
                  "second" => 1);

$tmpSeconds = $seconds;

$timeAgoStrings = array();

foreach ($timeUnits as $name => $numOfSeconds) {
   if ($seconds > $numOfSeconds) {
      $val = floor($tmpSeconds / $numOfSeconds);
      $agoStr = ($val > 1) ? $name."s" : $name;
      $timeAgoStrings[] = "$val $agoStr";
      $tmpSeconds = $tmpSeconds - $val; // cut the used time units off our tmpSeconds variable
   }
}
//check if we have more than one string - in case we do then we will pop the last val and add an "and" prefix before the last val instead of a comma
if (count($timeAgoStrings) > 1) {
   $lastString = array_pop($timeAgoStrings);
   $timeAgoStr = implode(", ",$timeAgoStrings)." and $lastString ago";
} else {
   $timeAgoStr = $timeAgoStrings[0]." ago";
}

Saggi Malachi
when giving it -1 please describe why
Saggi Malachi