note 76736 modified in function.time by danbrown

From: Date: Sun, 20 Jul 2008 04:19:48 +0000
Subject: note 76736 modified in function.time by danbrown
References: 1  Groups: php.notes 
Request: Send a blank email to php-notes+get-142126@lists.php.net to get a copy of this message
Fixed divide by zero warnings given by the timeDiff function. The change is that the for loop doesn't count down to 0 anymore, just 1. I dont think it has any side effects. <?php # max_detail_levels - how deep to go down? If max_detail_levels is set to 2, text will output something like "3 days 4 hours" instead of "3 days 4 hours 10 minutes 55 seconds" # precision_level - this is what rspenc29 was trying to accomplish. If you want to only report a minimum value of say 1 hour, then you should set this to "hour" function timeDiff($timestamp,$detailed=false, $max_detail_levels=8, $precision_level='second'){ $now = time(); #If the difference is positive "ago" - negative "away" ($timestamp >= $now) ? $action = 'away' : $action = 'ago'; # Set the periods of time $periods = array("second", "minute", "hour", "day", "week", "month", "year", "decade"); $lengths = array(1, 60, 3600, 86400, 604800, 2630880, 31570560, 315705600); $diff = ($action == 'away' ? $timestamp - $now : $now - $timestamp); $prec_key = array_search($precision_level,$periods); # round diff to the precision_level $diff = round(($diff/$lengths[$prec_key]))*$lengths[$prec_key]; # if the diff is very small, display for ex "just seconds ago" if ($diff <= 10) { $periodago = max(0,$prec_key-1); $agotxt = $periods[$periodago].'s'; return "just $agotxt $action"; } # Go from decades backwards to seconds $time = ""; for ($i = (sizeof($lengths) - 1); $i>0; $i--) { if($diff > $lengths[$i-1] && ($max_detail_levels > 0)) { # if the difference is greater than the length we are checking... continue $val = floor($diff / $lengths[$i-1]); # 65 / 60 = 1. That means one minute. 130 / 60 = 2. Two minutes.. etc $time .= $val ." ". $periods[$i-1].($val > 1 ? 's ' : ' '); # The value, then the name associated, then add 's' if plural $diff -= ($val * $lengths[$i-1]); # subtract the values we just used from the overall diff so we can find the rest of the information if(!$detailed) { $i = 0; } # if detailed is turn off (default) only show the first set found, else show all information $max_detail_levels--; } } # Basic error checking. if($time == "") { return "Error-- Unable to calculate time."; } else { return $time.$action; } } ?> [EDIT by danbrown AT php DOT net: Modifications from the original below up to this version were deleted from the user notes. The following people contributed bug fixes and code to reach this version: shdowhawk at gmail dot com nimit dot maru at dontspam-gmail dot com rspenc29 at gmail dot com sunjith ron at sdcausa dot org Credit for this function is due to the above authors in addition to the authors of the original and final version. --was-- Fixed divide by zero warnings given by the timeDiff function. The change is that the for loop doesn't count down to 0 anymore, just 1. I dont think it has any side effects. <?php # max_detail_levels - how deep to go down? If max_detail_levels is set to 2, text will output something like "3 days 4 hours" instead of "3 days 4 hours 10 minutes 55 seconds" # precision_level - this is what rspenc29 was trying to accomplish. If you want to only report a minimum value of say 1 hour, then you should set this to "hour" function timeDiff($timestamp,$detailed=false, $max_detail_levels=8, $precision_level='second'){ $now = time(); #If the difference is positive "ago" - negative "away" ($timestamp >= $now) ? $action = 'away' : $action = 'ago'; # Set the periods of time $periods = array("second", "minute", "hour", "day", "week", "month", "year", "decade"); $lengths = array(1, 60, 3600, 86400, 604800, 2630880, 31570560, 315705600); $diff = ($action == 'away' ? $timestamp - $now : $now - $timestamp); $prec_key = array_search($precision_level,$periods); # round diff to the precision_level $diff = round(($diff/$lengths[$prec_key]))*$lengths[$prec_key]; # if the diff is very small, display for ex "just seconds ago" if ($diff <= 10) { $periodago = max(0,$prec_key-1); $agotxt = $periods[$periodago].'s'; return "just $agotxt $action"; } # Go from decades backwards to seconds $time = ""; for ($i = (sizeof($lengths) - 1); $i>0; $i--) { if($diff > $lengths[$i-1] && ($max_detail_levels > 0)) { # if the difference is greater than the length we are checking... continue $val = floor($diff / $lengths[$i-1]); # 65 / 60 = 1. That means one minute. 130 / 60 = 2. Two minutes.. etc $time .= $val ." ". $periods[$i-1].($val > 1 ? 's ' : ' '); # The value, then the name associated, then add 's' if plural $diff -= ($val * $lengths[$i-1]); # subtract the values we just used from the overall diff so we can find the rest of the information if(!$detailed) { $i = 0; } # if detailed is turn off (default) only show the first set found, else show all information $max_detail_levels--; } } # Basic error checking. if($time == "") { return "Error-- Unable to calculate time."; } else { return $time.$action; } } ?> http://php.net/manual/en/function.time.php

« previous php.notes (#142126) next »