Alright, this is going to be a long one.
CODE
<?php
echo date_function($_GET['num_sec']);
function date_function($num_sec)
{
$sec = 0;
$min = 0;
$hour = 0;
$day = 0;
$month = 0;
$year = 0;
//Keep a few const to make the calculation easier to read
//You can use Const on the follow var, but yout need to put them outside this function.
$year_sec = 365 * 24 * 60 * 60;
$day_sec = 24 * 60 * 60;
$hour_sec = 60 * 60;
$min_sec = 60;
//Using modulus is a quick way out
$sec = $num_sec % 60;
//use floor to extract only the integer portion
$year = floor($num_sec / $year_sec);
$day = floor(($num_sec % $year_sec) / $day_sec);
$hour = floor(($num_sec % $day_sec) / $hour_sec);
$min = floor(($num_sec % $hour_sec) / $min_sec);
//Assuming 1 month = 30 days. You can't use 31 as it differ too much.
//30 * 12 = 360 (diff = 5)
//31 * 12 = 372 (diff = 7)
if ($day > 30)
{
$month = floor($day / 30);
$day = $day % 30;
}
//Return everything
return
($year > 0?
$year . " year" . ($year > 1? "s": "") . " "
: ""
) .
($month + $year > 0?
$month . " month" . ($month > 1? "s": "") . " "
: ""
) .
($day + $month + $year > 0?
$day . " day" . ($day > 1? "s": "") . " "
: ""
) .
($hour + $day + $month + $year > 0?
$hour . " hour" . ($hour > 1? "s": "") . " "
: ""
) .
($min + $hour + $day + $month + $year > 0?
$min . " min" . ($min > 1? "s": "") . " "
: ""
) .
($sec + $min + $hour + $day + $month + $year > 0?
$sec . " sec" . ($sec > 1? "s": "")
: ""
);
}
?>
I've included the way to call it. Let me explain a little how it works.
Initially, I declare the holding var for each of the unit. Then I declare a few var to be used as constant to hold the number of seconds for each unit. $year_sec would be the number of seconds per year. It helps if you need to read the code later. it also help to improve on the performance as php doesn't need to calculate it over and over again. Try compare this
CODE
$day = floor(($num_sec % $year_sec) / $day_sec);
with this
CODE
$day = floor(($num_sec % (365 * 24 * 60 * 60)) / (24 * 60 * 60));
or this
CODE
$day = floor(($num_sec % (31536000)) / (86400));
I don't calculate months yet, as it will be too complicate. I would rather calculate days first, then if it's more than 30, then calculate months.
The next step is the calculation. As you can see, i use modulus heavily, since it's easier. That's also how we would calculate using paper and pen, which is getting the remainder when we divide.
Without using modulus, it would look like the following, which is what I used to do before i learnt the magic of modulus
CODE
$day = floor((($num_sec - ($year * $year_sec)) / $day_sec);
It's harder to read and fix if there's a bug.
Next we calculate the months from the number of days we get.
The return might looks very complicated, basically I nested 2 tertiary operator. First is to decide if the value is zero, then don't append to the string. Second is to decide if the value is more than one, which we need to append an "s" behind. For the subsequent ones, I added up those var before it, so that it will still show if it's 0 when there's something before it. Like 2 hours 0min 3 secs. 2 hours 3 secs would look too weird. If you prefer the latter way, then remove the addition, just check for individual value.
Btw, in case you haven't know of, tertiary operator works like this
([test case]? [do this if true] : [do this if false])
It's simpler to read too instead of using if/else. Further more, you can't do everything inline if you're using if/else.
Reply