How to output elapsed time between moments in the correct grammatical case (depending on numerals) using PHP
here's a function that determines the elapsed time from the current moment to a given one
function GetValidTime( $year,$month, $day,$h,$m,$s)
{
$interval = time() - mktime($h,$m,$s,$month, $day, $year);
$interval = round($interval/60*60);
if($interval < 60)
$time = "$interval ".time_valid($interval, 's')." ago";
else if(($interval = intval($interval/60)) < 60)
$time = "$interval ".time_valid($interval, 'm')." ago";
else if(($interval = intval($interval/60)) < 24)
$time = "$interval ".time_valid($interval, 'h')." ago";
else if(($interval = intval($interval/24)) < 14)
$time = $interval." " .GetValidDay($interval)." ago";
else if(($weeks= intval($interval/7)) < 4)
$time = "$weeks weeks ago";
else if(($months= intval($interval/30.4)) < 12)
$time = "$months ".$this->time_valid($months, 'M')." ago";
else if(($years= intval($interval/365)) < 365)
$time = $years." ".GetValidYear($years)." ago"
;
return $time;
}
could you post the code for the function that forms the words month, year, second, hour, week in the correct grammatical case?
for example
2 minutes have passed
11 minutes have passed
1 minute has passed, etc..
function GetValidDay($daysCount)
{
$daysCount = (string)abs($daysCount);
$daysCase = "дней";
$lastChar = $daysCount[iconv_strlen($daysCount) - 1];
if (iconv_strlen($daysCount) >= 2 && $daysCount[iconv_strlen($daysCount) - 2] == '1')
{
// 10-19 days
}
else if ($lastChar == '1')
{
// 1, 21, 31 day
$daysCase = "день";
}
else if ($lastChar == '2' || $lastChar == '3' || $lastChar == '4')
{
// 2, 3, 4, 22, 33, 44 days
$daysCase = "дня";
}
return $daysCase;
}
function time_valid($time, $period)
{
$arr['s'] = array('секунда', 'секунды', 'секунд');
$arr['m'] = array('минута', 'минуты', 'минут');
$arr['h'] = array('час', 'часа', 'часов');
$arr['d'] = array('день', 'дня', 'дней');
$arr['M'] = array('месяц', 'месяца', 'месяцев');
$arr['Y'] = array('год', 'года', 'лет');
$arr['Y2'] = array('года', 'лет', 'лет');
$time_abs = abs($time);
$time_abs = intval(substr($time_abs, -2));
if ($time_abs > 19)
$time_abs = intval(substr($time_abs, -1));
$sec_arr[0] = array(2,3,4);
$sec_arr[1] = array(0,5,6,7,8,9);
if ($time_abs == 1)
$ret = $arr[$period][0];
else if (in_array($time_abs, $sec_arr[0]))
$ret = $arr[$period][1];
else if (($time_abs >= 5 AND $time_abs <= 20) OR $time_abs == 0)
$ret = $arr[$period][2];
return $ret;
}
function GetValidYear($year) {
$year = abs($year);
$t1 = $year % 10;
$t2 = $year % 100;
return ($t1 == 1 && $t2 != 11 ? "год" : ($t1 >= 2 && $t1 <= 4 && ($t2 < 10 || $t2 >= 20) ? "года" : "лет"));
}
why not combine all this into a single function?
by the way, note that if the time zones differ for the php interpreter and the mysql server,
then the time difference won't be correct,
so either set up the same time zone or take all data from a single source, for example from the mysql server
function GetTimeFromMysqlServer()
{
$db = &$this->MyDb;
$TimeFromMysqlServer = $db->getOne('SELECT now()');
// echo $db->lastQuery();
return $TimeFromMysqlServer;
}
second — when rounding the number of days in a month, there's a case where the algorithm could return that 0 months have passed; to fix this, add a determination of the exact number of days in the given month
$days_in_month= cal_days_in_month(CAL_GREGORIAN, date('m', $timeinput), date('Y', $timeinput));
in your function, 24 and 30.1 are the number of days in a month — this isn't correct, because if the month has a different number of days, the function returns that 0 months have passed....
instead of these numbers, in three places you need to replace them with the actual number of days in the month of a given year, using the variable $days_in_month
Comments