2010-04-22 2 views
26

Я в основном пытаюсь преобразовать временную метку Unix (функцию time()) в относительную дату/время, совместимую с прошлой и будущей датой. Таким образом, выходы могут быть:PHP: создание относительной даты/времени из временных меток

2 недели назад

1 час и 60 минут назад

15 минут и 54 секунд назад

после 10 минут и 15 секунд

Сначала я попытался закодировать это, но сделал огромную непосильную функцию, а затем я обыскал интернет в течение нескольких часов, но все, что я могу найти, это scri которые производят только одну часть времени (e.h: «1 час назад» без минут).

У вас есть сценарий, который уже делает это?

+0

Возможно, это может помочь вам: HTTP: // StackOverflow. com/questions/2643113/convert-2010-04-16-163000-to-tomorrow-днем/2643137 –

+1

Возможный дубликат [Как рассчитать relati ve time?] (http://stackoverflow.com/questions/11/how-do-i-calculate-relative-time) – hakre

ответ

44

Эта функция дает вам «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); 
    } 
} 
+0

, но это возвращает часы только с минут (например), верно? – KeyStroke

+1

ОК это? http://pastie.org/929624 – osm

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

Почему не сдирать так, что Друпал делает это - 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)); 
} 
?> 

Вы, вероятно, не нужна замена для т(), и вы можете сделать свою собственную вещь для format_plural довольно легко, как вам (возможно) не нужно поддерживать несколько языков. http://api.drupal.org/api/drupal/includes%21common.inc/function/format_plural/7

+1

Не будет ли защищена функция Drupal в соответствии с их лицензией на авторское право/с открытым исходным кодом? –

+0

@Rhino, это полностью зависит от того, что вы планируете делать с кодом. Если вы не распространяете исходный код, вы можете делать то, что вам нравится, с кодом GPL в Drupal. Если вы распространяете свой исходный код (за деньги или бесплатно), то использование части Drupal повлияет на лицензию, которую вы можете распространять в соответствии с (то есть, вам придется распространять ее под лицензией GPL самостоятельно) - http: // drupal. орг/лицензирование/чаво. –

+1

Да, я понимаю GPL, просто указывая, что вы можете указать ограничение в ответе. –

4

Мне нравится функция relativeTime xdebug. Проблема в том, что мне нужно, чтобы она имела некоторую детализацию.

Другими словами, остановитесь в считанные секунды или минуты, если решите. Так что теперь,

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

Маркус

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

Спасибо, мне понравилась ваша функция и использовал ее. – phansen

+1

приветствую :) @phansen – Ozzy

+1

Я также использовал слегка модифицированную версию этого в моем проекте. – VSG24

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

большое спасибо за это. Для тех, кто хочет использовать это, но показ часов ограничен только 24, замените 70 на 24 в третьем пункте периодов []. – Bayou

Смежные вопросы