2013-03-21 4 views
0

Мне интересно, какой из самых элегантных способов расчета человекообразного выпонного времени выдается за определенное количество секунд. Я хочу написать это на PHP.Лучший способ рассчитать человекообразное прошедшее время

Вот результат необходимо:

  • elapsedTimeInSeconds> один год, выход "# лет, # месяцев"
  • elapsedTimeInSeconds> один месяц, выход "# месяцев, # дней"
  • elapsedTimeInSeconds> один день, выходной "# дней, # часов"
  • elapsedTimeInSeconds> один час, выход "# часов, # минут"
  • elapsedTimeInSeconds> одна минута, выход "# минуты, секунды #"

Я пробовал разные решения, которые неудобны и полны условных утверждений, но я надеялся на более рекурсивный и «чистый код».

+0

Шесть условных утверждений не так уж плохи, хотя я бы поставил его как можно скорее (повторное использование кода и весь этот джаз). Я не уверен, что это хорошая рекурсивная проблема, потому что нет базового варианта. –

ответ

1

Я использую это:

function durationFormat($time) 
{ 
    if(gmdate("Y", $time)>1970) return (1970-gmdate("Y",$time)).gmdate(" \y\r\s ", $time).(gmdate("n",$time)-1).gmdate(" \m\o\n\t\h\s ", $time).(gmdate("j",$time)-1).gmdate(" \d\a\y\s H:i:s", $time); 
    if(gmdate("n", $time)>1) return (gmdate("n",$time)-1).gmdate(" \m\o\n\t\h\s ", $time).(gmdate("j",$time)-1).gmdate(" \d\a\y\s H:i:s", $time); 
    if(gmdate("j", $time)>1) return (gmdate("j",$time)-1).gmdate(" \d\a\y\s H:i:s", $time); 
    return gmdate("H:i:s", $time); 
} 

Это немного быстрый и грязный, но делает работу

ИЛИ

function durationFormat2($seconds) 
{ 
    $a_sec=1; 
    $a_min=$a_sec*60; 
    $an_hour=$a_min*60; 
    $a_day=$an_hour*24; 
    $a_week=$a_day*52; 
    //$a_month=$a_day*(floor(365/12)); 
    $a_month=$a_day*30; 
    $a_year=$a_day*365; 

    $params=2; 
    $text=''; 
    if($seconds>$a_year) 
    { 
     $years=floor($seconds/$a_year); 
     $text.=$years.' years '; 
     $seconds=$seconds-($years*$a_year); 
     $params--; 
    } 
    if($params==0) return $text; 
    if($seconds>$a_month) 
    { 
     $months=floor($seconds/$a_month); 
     $text.=$months.' months '; 
     $seconds=$seconds-($months*$a_month); 
     $params--; 
    } 
    if($params==0) return $text; 
    if($seconds>$a_week) 
    { 
     $weeks=floor($seconds/$a_week); 
     $text.=$weeks.' weeks '; 
     $seconds=$seconds-($months*$a_week); 
     $params--; 
    } 
    if($params==0) return $text; 
    if($seconds>$a_day) 
    { 
     $days=floor($seconds/$a_day); 
     $text.=$days.' days '; 
     $seconds=$seconds-($days*$a_day); 
     $params--; 
    } 
    if($params==0) return $text; 
    $H=gmdate("H", $seconds); 
    if($H>0) 
    { 
     $text.=$H.' hours '; 
     $params--; 
    } 
    if($params==0) return $text; 
    $M=gmdate("i", $seconds); 
    if($M>0) 
    { 
     $text.=$M.' minutes '; 
     $params--; 
    } 
    if($params==0) return $text; 
    $S=gmdate("s", $seconds); 
    $text.=$S.' seconds '; 

    return $text; 
} 
+1

+1 с разрешением; требования действительно говорят, однако, что текст имеет только две части. Возможно, в if-утверждениях, толкайте их в очередь, а в конце функции вытащите первые два и оттуда оттуда? –

+0

изменено, чтобы разрешить только 2 элемента. – Waygood

3

Я думаю, что это является более гибким, как вы можете легко добавлять новые единицы, такие как десятилетие, столетие и т. д., и код не изменится:

$names = array("seconds", "minutes", "hours", "days", "months", "years"); 
$values = array(1, 60, 3600, 24 * 3600, 30 * 24 * 3600, 365 * 24 * 3600); 

$time = ...elapsedTimeInSeconds...; 
for($i = count($values) - 1; $i > 0 && $time < $values[$i]; $i--); 
if($i == 0) { 
    echo intval($time/$values[$i]) . " " . $names[$i]; 
} else { 
    $t1 = intval($time/$values[$i]); 
    $t2 = intval(($time - $t1 * $values[$i])/$values[$i - 1]); 
    echo "$t1 " . $names[$i] . ", $t2 " . $names[$i - 1]; 
} 
+0

Интересно, я попробую это как можно скорее. – cellover

+0

@ cellover, как быстро ваш ASAP? :) – Andron

+0

ASAP обычно означает «от нескольких лет до столетия». Я попробовал, но, наконец, решил пойти на более читаемое решение, как я упоминал в этом ответе: http://stackoverflow.com/questions/15548792/best-way-to-calculate-human-readable-elapsed-time/15551814 # 15551814 – cellover

2

Спасибо за ваши предложения.

В основном я использовал предложения Waygood и ChrisForrence для этого метода. Я попытался максимально упростить его и представил простые аргументы, такие как уровень детализации и разделитель (для строки вывода).

public function elapsedTimeHumanReadable($date = null, $detailLevel = 2, $delimiter = ' et ') 
{ 
    if($date === null) 
    { 
     $date = self::now(); 
    } 

    $sec = $this->elapsedSecond($date); 

    $a_sec = 1; 
    $a_min = $a_sec * 60; 
    $an_hour = $a_min * 60; 
    $a_day = $an_hour * 24; 
    $a_month = $a_day * 30; 
    $a_year = $a_day * 365; 

    $text = ''; 
    $resultStack = array(); 
    if($sec >= $a_year) 
    { 
     $years = floor($sec/$a_year); 
     $text .= $years . $this->plural($years, ' an'); 
     $sec = $sec - ($years * $a_year); 
     array_push($resultStack, $text); 
    } 

    if($sec >= $a_month) 
    { 
     $months = floor($sec/$a_month); 
     $text = $months . ' mois'; 
     $sec = $sec - ($months * $a_month); 
     array_push($resultStack, $text); 
    } 

    if($sec >= $a_day) 
    { 
     $days = floor($sec/$a_day); 
     $text = $days . $this->plural($days, ' jour'); 
     $sec = $sec - ($days * $a_day); 
     array_push($resultStack, $text); 
    } 

    if($sec >= $an_hour) 
    { 
     $hours = floor($sec/$an_hour); 
     $text = $hours . $this->plural($hours, ' heure'); 
     $sec = $sec - ($hours * $an_hour); 
     array_push($resultStack, $text); 
    } 

    if($sec >= $a_min) 
    { 
     $minutes = floor($sec/$a_min); 
     $text = $minutes . $this->plural($minutes, ' minute'); 
     $sec = $sec - ($minutes * $a_min); 
     array_push($resultStack, $text); 
    } 

    if($sec >= $a_sec) 
    { 
     $seconds = floor($sec/$a_sec); 
     $text = $sec . $this->plural($seconds, ' seconde'); 
     $sec = $sec - ($sec * $a_sec); 
     array_push($resultStack, $text); 
    } 

    $result = $resultStack[0]; 
    for($i = 1; $i <= $detailLevel - 1; $i++) 
    { 
     if(!empty($resultStack[$i])) 
     { 
      $result .= $delimiter . $resultStack[$i]; 
     } 
    } 

    return $result; 
} 

Я также добавил очень простую множественную функцию, чтобы вернуть единицу времени в правильной грамматической моде:

public function plural($value, $unit) 
{ 
    if($value > 1) 
    { 
     return $unit . 's'; 
    } 
    else 
    { 
     return $unit; 
    } 
} 

Я не очень доволен для цикла, но это на самом деле работает отлично.

В любом случае, большое вам спасибо за помощь!