PHP — конвертировать миллисекунды в часы : минуты : секунды.fractional

У меня есть скрипт, который принимает значение в секундах (до 2 знаков после запятой доли секунды):

$seconds_input = 23.75

Затем я конвертирую его в миллисекунды:

$milliseconds = $seconds_input * 1000; // --> 23750

И затем я хочу отформатировать его так:

H:M:S.x // --> 0:0:23.75

Где «x» - доля секунды (сколько бы знаков после запятой ни было).

Любая помощь? Кажется, я не могу уложить это в голове. Я пытался использовать gmdate(), но он продолжал обрезать доли секунды.

Спасибо.


person AJB    schedule 21.01.2011    source источник
comment
us.php.net/manual/en/function.sprintf.php   -  person scragz    schedule 21.01.2011
comment
Просто хотел добавить, что это должно было создать входное значение для поля -ss FFMPEG. Включение долей секунды улучшает детализацию целевого кадра и дает пользователю почти точный кадр, который он просматривает в видеопроигрывателе. Еще раз всем спасибо, вы сэкономили мне кучу времени.   -  person AJB    schedule 22.01.2011


Ответы (4)


Мой взгляд

function formatSeconds( $seconds )
{
  $hours = 0;
  $milliseconds = str_replace( "0.", '', $seconds - floor( $seconds ) );

  if ( $seconds > 3600 )
  {
    $hours = floor( $seconds / 3600 );
  }
  $seconds = $seconds % 3600;


  return str_pad( $hours, 2, '0', STR_PAD_LEFT )
       . gmdate( ':i:s', $seconds )
       . ($milliseconds ? ".$milliseconds" : '')
  ;
}

А потом тест

$testData = array(
    23,              // Seconds, w/o millis
    23.75,           // Seconds, w/millis
    23.75123456789,  // Lots of millis
    123456789.75    // Lots of seconds
);

foreach ( $testData as $seconds )
{
  echo formatSeconds( $seconds ), PHP_EOL;
}

который дает

00:00:23
00:00:23.75
00:00:23.75123456789
34293:33:09.75
person Peter Bailey    schedule 21.01.2011
comment
Я люблю переполнение стека. Спасибо всем. Я даже не уверен, какой из них мне больше нравится. - person AJB; 22.01.2011
comment
Я новичок в php, я обнаружил, что @ircmaxell не работает для всех значений. В моем случае значение ms было: 1189107. Я получаю около 23 часов, используя функцию ircmaxell, и 00.19:49, используя вашу. - person zengr; 30.11.2012
comment
@Peter Bailey - я думаю, что строка 6 должна выглядеть так: if ( $seconds >= 3600 ) - т.е. если $seconds больше или равно 3600. Это гарантирует, что ровно 1 час, т.е. 3600 секунд, выводится как 01:00:00, а не 00:00:00 без этой настройки. Спасибо за функцию - я использую ее для наблюдения за производительностью сайта Drupal. - person therobyouknow; 10.01.2020

Редактировать: Ну, я немного поторопился. Вот один из способов сделать то, что вы просите:

function formatMilliseconds($milliseconds) {
    $seconds = floor($milliseconds / 1000);
    $minutes = floor($seconds / 60);
    $hours = floor($minutes / 60);
    $milliseconds = $milliseconds % 1000;
    $seconds = $seconds % 60;
    $minutes = $minutes % 60;

    $format = '%u:%02u:%02u.%03u';
    $time = sprintf($format, $hours, $minutes, $seconds, $milliseconds);
    return rtrim($time, '0');
}
person ircmaxell    schedule 21.01.2011
comment
Конечно, не единственный способ, но он умный и простой. - person GolezTrol; 21.01.2011
comment
Насколько я понимаю, они говорят о продолжительности, а не о дате и времени. - person scragz; 21.01.2011
comment
Это может быть проблемой, но только если продолжительность превышает 24 часа. - person GolezTrol; 21.01.2011
comment
Да, я только что попробовал это, и я получаю 18: Dec: st.0. Я думаю, что это правильное направление, спасибо ircmaxell. - person AJB; 22.01.2011
comment
вам нужно убедиться, что начальные нули включены в поле миллисекунд. 1 миллисекунда должна читаться как 0,001, а не как 0,1, как это выдает приведенный выше код. - person Alnitak; 22.01.2011
comment
Я люблю переполнение стека. Спасибо всем. Я даже не уверен, какой из них мне больше нравится. - person AJB; 22.01.2011
comment
Это решение не работает со всеми возможными тестовыми данными. Он неправильно дополняет часы нулями, может оставлять конечные десятичные точки и подвержен ошибкам округления с плавающей запятой. - person Peter Bailey; 22.01.2011
comment
@Peter: Он может оставлять конечные десятичные точки? Где? Что касается часов Zero-padding, нужно ли это? Это определенно подвержено ошибкам округления с плавающей запятой, но сначала выполняются значения с более низкой точностью, так что это не должно сильно влиять на ответ для большинства разумных входных данных... Если я не ошибаюсь... - person ircmaxell; 22.01.2011
comment
Я проверил ваш рядом с моим с теми же тестовыми данными - различия были очевидны. Имейте в виду, я не говорю, что мой вариант правильный - я позволил себе некоторую вольность в интерпретации требований из того, что было не сказано. - person Peter Bailey; 22.01.2011
comment
@Peter: Единственные две проблемы были, когда у вас были нецелые миллисекунды и очень большая секунда. Но это было основано на предположении выше, что у него было целое число миллисекунд. Я предполагаю, что лучшее решение зависит от требований (о которых мы здесь только догадываемся) - person ircmaxell; 22.01.2011

Мой гораздо менее читабелен, так что он должен быть лучше. :п

В основном та же идея, что и в версии @ircmaxell. Он обрезает конечные «0» и даже пропускает последние «.». разделитель, если миллисекунды равны 0.

<?

function format_period($seconds_input)
{
  $hours = (int)($minutes = (int)($seconds = (int)($milliseconds = (int)($seconds_input * 1000)) / 1000) / 60) / 60;
  return $hours.':'.($minutes%60).':'.($seconds%60).(($milliseconds===0)?'':'.'.rtrim($milliseconds%1000, '0'));
}

echo format_period(23.75);
person GolezTrol    schedule 21.01.2011

если вы действительно хотите сделать это с помощью функции даты, вы правы, вам нужно иметь дело с миллисекундами извне, основано только на секундных метках времени.

вы можете сделать что-то вроде этого:

<?
$input = "23.75";
$seconds = floor($input);
$date = DateTime::createFromFormat('s', floor($seconds));
$ms = ($input-$seconds);
if($ms == 0) {
$ms = "";
} else { 
$ms = ltrim($ms,"0,");
}
echo $date->format('H:i:s').$ms;

но помните о переполнении часов, если ваши часы превышают 24, вы, вероятно, в конечном итоге отбросите дни.

в вашем случае я бы сказал, что ваш подход к полу для получения секунд правильный, и тогда вам, вероятно, следует просто использовать арифметику по модулю следующим образом:

<?
$totalsecs = 86400*10;

$secs = $totalsecs%60;

echo "secs: $secs \n";

$minutes = ($totalsecs - $secs) % (60*60);
?>

и так далее..

person The Surrican    schedule 21.01.2011