可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I\'m basically trying to convert a Unix timestamp (the time() function) to a relative date/time that\'s both compatible with past and future date. So outputs could be:
2 weeks ago
1 hour and 60 minutes ago
15 minutes and 54 seconds ago
after 10 minutes and 15 seconds
First I tried to code this, but made a huge unmaintainable function, and then I searched the internet for a couple of hours, yet all I can find are scripts that produce only one part of the time (e.h: \"1 hour ago\" without the minutes).
Do you have a script that already does this?
回答1:
This function gives you \"1 hour ago\" or \"Tomorrow\" like results between \'now\' and \'specific timestamp\'.
function time2str($ts)
{
if(!ctype_digit($ts))
$ts = strtotime($ts);
$diff = time() - $ts;
if($diff == 0)
return \'now\';
elseif($diff > 0)
{
$day_diff = floor($diff / 86400);
if($day_diff == 0)
{
if($diff < 60) return \'just now\';
if($diff < 120) return \'1 minute ago\';
if($diff < 3600) return floor($diff / 60) . \' minutes ago\';
if($diff < 7200) return \'1 hour ago\';
if($diff < 86400) return floor($diff / 3600) . \' hours ago\';
}
if($day_diff == 1) return \'Yesterday\';
if($day_diff < 7) return $day_diff . \' days ago\';
if($day_diff < 31) return ceil($day_diff / 7) . \' weeks ago\';
if($day_diff < 60) return \'last month\';
return date(\'F Y\', $ts);
}
else
{
$diff = abs($diff);
$day_diff = floor($diff / 86400);
if($day_diff == 0)
{
if($diff < 120) return \'in a minute\';
if($diff < 3600) return \'in \' . floor($diff / 60) . \' minutes\';
if($diff < 7200) return \'in an hour\';
if($diff < 86400) return \'in \' . floor($diff / 3600) . \' hours\';
}
if($day_diff == 1) return \'Tomorrow\';
if($day_diff < 4) return date(\'l\', $ts);
if($day_diff < 7 + (7 - date(\'w\'))) return \'next week\';
if(ceil($day_diff / 7) < 4) return \'in \' . ceil($day_diff / 7) . \' weeks\';
if(date(\'n\', $ts) == date(\'n\') + 1) return \'next month\';
return date(\'F Y\', $ts);
}
}
回答2:
function relativeTime($time) {
$d[0] = array(1,\"second\");
$d[1] = array(60,\"minute\");
$d[2] = array(3600,\"hour\");
$d[3] = array(86400,\"day\");
$d[4] = array(604800,\"week\");
$d[5] = array(2592000,\"month\");
$d[6] = array(31104000,\"year\");
$w = array();
$return = \"\";
$now = time();
$diff = ($now-$time);
$secondsLeft = $diff;
for($i=6;$i>-1;$i--)
{
$w[$i] = intval($secondsLeft/$d[$i][0]);
$secondsLeft -= ($w[$i]*$d[$i][0]);
if($w[$i]!=0)
{
$return.= abs($w[$i]) . \" \" . $d[$i][1] . (($w[$i]>1)?\'s\':\'\') .\" \";
}
}
$return .= ($diff>0)?\"ago\":\"left\";
return $return;
}
Usage:
echo relativeTime((time()-256));
4 minutes 16 seconds ago
回答3:
Here is what I\'ve written. Displays a past date relative to today\'s date.
/**
* @param $date integer of unixtimestamp format, not actual date type
* @return string
*/
function zdateRelative($date)
{
$now = time();
$diff = $now - $date;
if ($diff < 60){
return sprintf($diff > 1 ? \'%s seconds ago\' : \'a second ago\', $diff);
}
$diff = floor($diff/60);
if ($diff < 60){
return sprintf($diff > 1 ? \'%s minutes ago\' : \'one minute ago\', $diff);
}
$diff = floor($diff/60);
if ($diff < 24){
return sprintf($diff > 1 ? \'%s hours ago\' : \'an hour ago\', $diff);
}
$diff = floor($diff/24);
if ($diff < 7){
return sprintf($diff > 1 ? \'%s days ago\' : \'yesterday\', $diff);
}
if ($diff < 30)
{
$diff = floor($diff / 7);
return sprintf($diff > 1 ? \'%s weeks ago\' : \'one week ago\', $diff);
}
$diff = floor($diff/30);
if ($diff < 12){
return sprintf($diff > 1 ? \'%s months ago\' : \'last month\', $diff);
}
$diff = date(\'Y\', $now) - date(\'Y\', $date);
return sprintf($diff > 1 ? \'%s years ago\' : \'last year\', $diff);
}
回答4:
I love the relativeTime function by xdebug. Problem is I needed it to have some granularity.
In other words stop at seconds or minutes if I decide.
So now,
echo fTime(strtotime(\'-23 hours 5 minutes 55 seconds\'),0);
would show,
23 hours, 5 minutes ago
Instead of
23 hours, 5 minutes, 55 seconds ago
I also wanted it to NOT go lower in the array if it reached one of the higher time amounts.
So if it shows years, I only want to show years and months.
So now,
echo fTime(strtotime(\'-1 year 2 months 3 weeks 4 days 16 hours 15 minutes 22 seconds\'),0);
Would show
1 year, 2 months ago
Instead of
1 year, 2 months, 3 weeks, 4 days, 16 hours, 15 minutes, 22 seconds ago
The following code change did what I needed. Props go to xdebug first of course.
Hopefully someone else might find it useful:
function fTime($time, $gran=-1) {
$d[0] = array(1,\"second\");
$d[1] = array(60,\"minute\");
$d[2] = array(3600,\"hour\");
$d[3] = array(86400,\"day\");
$d[4] = array(604800,\"week\");
$d[5] = array(2592000,\"month\");
$d[6] = array(31104000,\"year\");
$w = array();
$return = \"\";
$now = time();
$diff = ($now-$time);
$secondsLeft = $diff;
$stopat = 0;
for($i=6;$i>$gran;$i--)
{
$w[$i] = intval($secondsLeft/$d[$i][0]);
$secondsLeft -= ($w[$i]*$d[$i][0]);
if($w[$i]!=0)
{
$return.= abs($w[$i]) . \" \" . $d[$i][1] . (($w[$i]>1)?\'s\':\'\') .\" \";
switch ($i) {
case 6: // shows years and months
if ($stopat==0) { $stopat=5; }
break;
case 5: // shows months and weeks
if ($stopat==0) { $stopat=4; }
break;
case 4: // shows weeks and days
if ($stopat==0) { $stopat=3; }
break;
case 3: // shows days and hours
if ($stopat==0) { $stopat=2; }
break;
case 2: // shows hours and minutes
if ($stopat==0) { $stopat=1; }
break;
case 1: // shows minutes and seconds if granularity is not set higher
break;
}
if ($i===$stopat) { break 0; }
}
}
$return .= ($diff>0)?\"ago\":\"left\";
return $return;
}
Marcus
回答5:
I needed one to give me results as below, so I wrote my own. Hopefully, this will help somebody.
Example usage:
$datetime = \"2014-08-13 12:52:48\";
echo getRelativeTime($datetime); //10 hours ago
echo getRelativeTime($datetime, 1); //10 hours ago
echo getRelativeTime($datetime, 2); //10 hours and 50 minutes ago
echo getRelativeTime($datetime, 3); //10 hours, 50 minutes and 50 seconds ago
echo getRelativeTime($datetime, 4); //10 hours, 50 minutes and 50 seconds ago
Code:
public function getRelativeTime($datetime, $depth=1) {
$units = array(
\"year\"=>31104000,
\"month\"=>2592000,
\"week\"=>604800,
\"day\"=>86400,
\"hour\"=>3600,
\"minute\"=>60,
\"second\"=>1
);
$plural = \"s\";
$conjugator = \" and \";
$separator = \", \";
$suffix1 = \" ago\";
$suffix2 = \" left\";
$now = \"now\";
$empty = \"\";
# DO NOT EDIT BELOW
$timediff = time()-strtotime($datetime);
if ($timediff == 0) return $now;
if ($depth < 1) return $empty;
$max_depth = count($units);
$remainder = abs($timediff);
$output = \"\";
$count_depth = 0;
$fix_depth = true;
foreach ($units as $unit=>$value) {
if ($remainder>$value && $depth-->0) {
if ($fix_depth) {
$max_depth -= ++$count_depth;
if ($depth>=$max_depth) $depth=$max_depth;
$fix_depth = false;
}
$u = (int)($remainder/$value);
$remainder %= $value;
$pluralise = $u>1?$plural:$empty;
$separate = $remainder==0||$depth==0?$empty:
($depth==1?$conjugator:$separator);
$output .= \"{$u} {$unit}{$pluralise}{$separate}\";
}
$count_depth++;
}
return $output.($timediff<0?$suffix2:$suffix1);
}
回答6:
You can use Carbon via packagist, just amazing :)
https://github.com/briannesbitt/Carbon#api-humandiff
回答7:
Here is what I use for past times:
function zdateRelative($date)
{
$diff = time() - $date;
$periods[] = [60, 1, \'%s seconds ago\', \'a second ago\'];
$periods[] = [60*100, 60, \'%s minutes ago\', \'one minute ago\'];
$periods[] = [3600*70, 3600, \'%s hours ago\', \'an hour ago\'];
$periods[] = [3600*24*10, 3600*24, \'%s days ago\', \'yesterday\'];
$periods[] = [3600*24*30, 3600*24*7, \'%s weeks ago\', \'one week ago\'];
$periods[] = [3600*24*30*30, 3600*24*30, \'%s months ago\', \'last month\'];
$periods[] = [INF, 3600*24*265, \'%s years ago\', \'last year\'];
foreach ($periods as $period) {
if ($diff > $period[0]) continue;
$diff = floor($diff / $period[1]);
return sprintf($diff > 1 ? $period[2] : $period[3], $diff);
}
}
回答8:
Why not rip off the way that drupal does it - http://api.drupal.org/api/drupal/includes%21common.inc/function/format_interval/7
<?php
function format_interval($interval, $granularity = 2, $langcode = NULL) {
$units = array(
\'1 year|@count years\' => 31536000,
\'1 month|@count months\' => 2592000,
\'1 week|@count weeks\' => 604800,
\'1 day|@count days\' => 86400,
\'1 hour|@count hours\' => 3600,
\'1 min|@count min\' => 60,
\'1 sec|@count sec\' => 1,
);
$output = \'\';
foreach ($units as $key => $value) {
$key = explode(\'|\', $key);
if ($interval >= $value) {
$output .= ($output ? \' \' : \'\') . format_plural(floor($interval / $value), $key[0], $key[1], array(), array(\'langcode\' => $langcode));
$interval %= $value;
$granularity--;
}
if ($granularity == 0) {
break;
}
}
return $output ? $output : t(\'0 sec\', array(), array(\'langcode\' => $langcode));
}
?>
You probably don\'t need a replacement for t() and you could do your own thing for format_plural pretty easily as you (probably) don\'t have to support multiple languages. http://api.drupal.org/api/drupal/includes%21common.inc/function/format_plural/7