PHP:从时间戳生成相对日期/时间

时间:2010-04-22 11:55:46

标签: php time timestamp relative-date

我基本上试图将Unix时间戳(time()函数)转换为兼容过去和未来日期的相对日期/时间。所以产出可能是:

  

2周前

     

1小时60分钟前

     

15分54秒前

     

10分15秒后

首先我尝试对此进行编码,但是创建了一个巨大的无法维护的功能,然后我在互联网上搜索了几个小时,但我只能找到只产生一部分时间的脚本(呃:“1小时以前“没有分钟”。

你有一个已经这样做的脚本吗?

9 个答案:

答案 0 :(得分:48)

此功能为您提供“1小时前”或“明天”,就像“现在”和“特定时间戳”之间的结果一样。

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);
    }
}

答案 1 :(得分:13)

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;
}

用法:

echo relativeTime((time()-256));
4 minutes 16 seconds ago

答案 2 :(得分:9)

这是我写的。显示相对于今天日期的过去日期。

/**
 * @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);
}

答案 3 :(得分:5)

我喜欢 xdebug 的relativeTime函数。问题是我需要它有一些粒度。

换句话说,如果我决定,请在秒或分钟停止。 现在,

echo fTime(strtotime('-23 hours 5 minutes 55 seconds'),0); 

会显示,

  

23小时,5分钟前

而不是

  

23小时,5分钟,55秒前

如果达到较高时间量之一,我也希望它不会在数组中降低。 因此,如果它显示多年,我只想显示年和月。 现在,

echo fTime(strtotime('-1 year 2 months 3 weeks 4 days 16 hours 15 minutes 22 seconds'),0); 

会显示

  

1年,2个月前

而不是

  

1年,2个月,3周,4天,16小时,15分钟,22秒之前

以下代码更改完成了我的需要。道具首先去xdebug。 希望其他人可能会发现它很有用:

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;
}

马库斯

答案 4 :(得分:3)

我需要一个给我结果如下,所以我写了自己的。希望这会对某人有所帮助。

使用示例:

$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  

代码:

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);
}

答案 5 :(得分:1)

你可以使用Carbon via packagist,真是太棒了:) https://github.com/briannesbitt/Carbon#api-humandiff

答案 6 :(得分:1)

以下是我过去使用的内容:

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);
  }
}

答案 7 :(得分:0)

为什么不扯掉drupal的方式 - 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));
}
?>

您可能不需要替换t(),并且您可以非常轻松地为format_plural做自己的事情,因为您(可能)不必支持多种语言。 http://api.drupal.org/api/drupal/includes%21common.inc/function/format_plural/7

答案 8 :(得分:0)

应该很容易适应不同的格式。这个简单的函数只适用于过去的时间戳。

// return relative date/time string from timestamp
// [n yrs] [n mos] [n days] h:i:s
function relative_time(int $time): string
{
        $dt = new DateTime();
        $dt->setTimestamp($time);
        $diff = (new DateTime())->diff($dt);

        $s = "";
        if ($diff->y) $s .= " {$diff->y} " . (($diff->y > 1) ? "yrs" : "yr");
        if ($diff->m) $s .= " {$diff->m} " . (($diff->m > 1) ? "mos" : "mo");
        if ($diff->d) $s .= " {$diff->d} " . (($diff->d > 1) ? "days" : "day");
        $s .= sprintf(" %02d:%02d:%02d", $diff->h, $diff->i, $diff->s);
        return trim($s);
}