Print

Convert Past Date to Time Ago in PHP

What?
Just a quick note to refine a function that will take a date in the past and return the number of years, months, weeks, days, hours, minutes and seconds.

Why?
Here are some examples of what we want to achieve:
copyraw
1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds  // full string
1 year 3 weeks 5 hours 7 seconds                            // where shown values are not zero
  1.  1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds  // full string 
  2.  1 year 3 weeks 5 hours 7 seconds                            // where shown values are not zero 
Actually we just want the first two words of those strings:
copyraw
3 days ago          // where event is 3 days ago or just over but less than 4 days ago
1 week ago          // where event is just over 1 week ago but less than 2 weeks ago
  1.  3 days ago          // where event is 3 days ago or just over but less than 4 days ago 
  2.  1 week ago          // where event is just over 1 week ago but less than 2 weeks ago 

How?
I know there are so many examples out there that do this perhaps better but this one I understand and can customize to fit my needs.

This PHP function accepts as parameter a SQL date (or date format that strtotime() can convert) and outputs the largest unit (for example "1 year" not "1 year 2 months 3 days, etc...").
copyraw
function getTimeAgo($p_Date) {

    // get seconds ago
    $v_Seconds = strtotime('now') - strtotime($p_Date);

    // set unit labels
    $a_UnitLabels = array('year','month','week','day','hour','minute','second');

    // set unit values
    $a_UnitValues = array(
        floor($v_Seconds / 31536000),
        floor(($v_Seconds % 31536000) / 2592000),
        floor(($v_Seconds % 2592000) / 604800),
        floor(($v_Seconds % 604800) / 86400),
        floor(($v_Seconds % 86400) / 3600),
        floor(($v_Seconds % 3600) / 60),
        floor($v_Seconds % 60),
    ); 

    // initiate array (for array_slice)
    $a_UnitPairs = array();

    // loop concatenating unit value to its label
    for($i=0;$i<count($a_UnitLabels);$i++){

        // pair up if greater than zero
        $v_Str  = $a_UnitValues[$i]>0 ? $a_UnitValues[$i].' '.$a_UnitLabels[$i] : '';

        // grammar for plural/singular (should always be a positive number)
        $v_Str .= $a_UnitValues[$i]>1 ? 's' : '';

        // only add to array if not empty/zero
        if($v_Str!='') $a_UnitPairs[] = $v_Str;
    }

    // take first item of array (round up to largest unit)
    $v_ReturnStr = $a_UnitPairs[0].' ago';

    // return
    return $v_ReturnStr;

}
  1.  function getTimeAgo($p_Date) { 
  2.   
  3.      // get seconds ago 
  4.      $v_Seconds = strtotime('now') - strtotime($p_Date)
  5.   
  6.      // set unit labels 
  7.      $a_UnitLabels = array('year','month','week','day','hour','minute','second')
  8.   
  9.      // set unit values 
  10.      $a_UnitValues = array( 
  11.          floor($v_Seconds / 31536000), 
  12.          floor(($v_Seconds % 31536000) / 2592000), 
  13.          floor(($v_Seconds % 2592000) / 604800), 
  14.          floor(($v_Seconds % 604800) / 86400), 
  15.          floor(($v_Seconds % 86400) / 3600), 
  16.          floor(($v_Seconds % 3600) / 60), 
  17.          floor($v_Seconds % 60), 
  18.      )
  19.   
  20.      // initiate array (for array_slice) 
  21.      $a_UnitPairs = array()
  22.   
  23.      // loop concatenating unit value to its label 
  24.      for($i=0;$i<count($a_UnitLabels);$i++){ 
  25.   
  26.          // pair up if greater than zero 
  27.          $v_Str  = $a_UnitValues[$i]>0 ? $a_UnitValues[$i].' '.$a_UnitLabels[$i] : ''
  28.   
  29.          // grammar for plural/singular (should always be a positive number) 
  30.          $v_Str .= $a_UnitValues[$i]>1 ? 's' : ''
  31.   
  32.          // only add to array if not empty/zero 
  33.          if($v_Str!='') $a_UnitPairs[] = $v_Str
  34.      } 
  35.   
  36.      // take first item of array (round up to largest unit) 
  37.      $v_ReturnStr = $a_UnitPairs[0].' ago'
  38.   
  39.      // return 
  40.      return $v_ReturnStr
  41.   
  42.  } 

Usage
copyraw
$v_Str = getTimeAgo('2019-05-16 19:30:00');
// If (at time of print) this date is 17 minutes and 5 seconds ago
// then $v_Str = "17 minutes ago"
  1.  $v_Str = getTimeAgo('2019-05-16 19:30:00')
  2.  // if (at time of print) this date is 17 minutes and 5 seconds ago 
  3.  // then $v_Str = "17 minutes ago" 

Or how about
copyraw
$v_Str = getTimeAgo('-1 week 2 days 4 hours 2 seconds');
// yields "1 week ago"

$v_Str = getTimeAgo('last Monday');
// yields "3 days ago" (it's Thursday)

$v_Str = getTimeAgo('first day of this month');
// yields "15 days ago" (it's the 16th)
  1.  $v_Str = getTimeAgo('-1 week 2 days 4 hours 2 seconds')
  2.  // yields "1 week ago" 
  3.   
  4.  $v_Str = getTimeAgo('last Monday')
  5.  // yields "3 days ago" (it's Thursday) 
  6.   
  7.  $v_Str = getTimeAgo('first day of this month')
  8.  // yields "15 days ago" (it's the 16th) 

The same PHP function as above but somewhat minimized
copyraw
function getTimeAgo($p){
    $s = strtotime('now') - strtotime($p);
    $a1 = array('year','month','week','day','hour','minute','second');
    $a2 = array(
        floor($s/31536000),
        floor(($s%31536000)/2592000),
        floor(($s%2592000)/604800),
        floor(($s%604800)/86400),
        floor(($s%86400)/3600),
        floor(($s%3600)/60),
        floor($s%60),
    ); 
    for($i=0;$i<count($a1);$i++){
        $str  = $a2[$i]>0 ? $a2[$i].' '.$a1[$i] : '';
        $str .= $a2[$i]>1 ? 's' : '';
        if($str!='') break;
    }
    return $str.' ago';
}
  1.  function getTimeAgo($p){ 
  2.      $s = strtotime('now') - strtotime($p)
  3.      $a1 = array('year','month','week','day','hour','minute','second')
  4.      $a2 = array( 
  5.          floor($s/31536000), 
  6.          floor(($s%31536000)/2592000), 
  7.          floor(($s%2592000)/604800), 
  8.          floor(($s%604800)/86400), 
  9.          floor(($s%86400)/3600), 
  10.          floor(($s%3600)/60), 
  11.          floor($s%60), 
  12.      )
  13.      for($i=0;$i<count($a1);$i++){ 
  14.          $str  = $a2[$i]>0 ? $a2[$i].' '.$a1[$i] : ''
  15.          $str .= $a2[$i]>1 ? 's' : ''
  16.          if($str!='') break
  17.      } 
  18.      return $str.' ago'
  19.  } 

If you want the first 4 words but minified (eg. "1 week and 2 days ago"):
copyraw
function getTimeAgo($p) {
    $s = strtotime('now') - strtotime($p);
    $a1 = array('year','month','week','day','hour','minute','second');
    $a2 = array(
        floor($s / 31536000),
        floor(($s % 31536000) / 2592000),
        floor(($s % 2592000) / 604800),
        floor(($s % 604800) / 86400),
        floor(($s % 86400) / 3600),
        floor(($s % 3600) / 60),
        floor($s % 60),
    ); 
    for($i=0;$i<count($a1);$i++){
        $v  = $a2[$i]>0 ? $a2[$i].' '.$a1[$i] : '';
        $v .= $a2[$i]>1 ? 's' : '';
        if($v!='') $a3[] = $v;
    }
    return implode(' and ', array_slice($a3,0,2)).' ago';
}
  1.  function getTimeAgo($p) { 
  2.      $s = strtotime('now') - strtotime($p)
  3.      $a1 = array('year','month','week','day','hour','minute','second')
  4.      $a2 = array( 
  5.          floor($s / 31536000), 
  6.          floor(($s % 31536000) / 2592000), 
  7.          floor(($s % 2592000) / 604800), 
  8.          floor(($s % 604800) / 86400), 
  9.          floor(($s % 86400) / 3600), 
  10.          floor(($s % 3600) / 60), 
  11.          floor($s % 60), 
  12.      )
  13.      for($i=0;$i<count($a1);$i++){ 
  14.          $v  = $a2[$i]>0 ? $a2[$i].' '.$a1[$i] : ''
  15.          $v .= $a2[$i]>1 ? 's' : ''
  16.          if($v!='') $a3[] = $v
  17.      } 
  18.      return implode(' and ', array_slice($a3,0,2)).' ago'
  19.  } 

When could I possibly want to do this? Well I've previously used this for password change reminders but on this occasion for a listing of reviews laid out as per the following screenshot:
Screenshot of narrow column reviews
Category: Personal Home Page :: Article: 679