PHP——将毫秒转换为时:分:秒.小数

18

我有一个脚本,它接受一个以秒为单位的值(保留小数点后两位):

$seconds_input = 23.75

然后我将其转换为毫秒:

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

然后我想这样格式化它:

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

这里的 'x' 表示小数部分秒数(小数点后面的数字)。

需要帮助吗?我好像无法理解这个。我尝试使用 gmdate() 函数,但它一直裁剪掉了小数秒。

谢谢。


http://us.php.net/manual/en/function.sprintf.php - scragz
只是想补充一下,这是为了生成FFMPEG的-ss字段的输入值。通过包含小数秒,它可以提高目标帧的粒度,并几乎为用户在视频播放器中查看的确切帧提供了准确的帧。再次感谢大家,你们节省了我大量的时间。 - AJB
4个回答

30

编辑:好的,我有点匆忙。这里有一种方法可以做到你所要求的:

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

当然不是唯一的方式,但它聪明而简单。 - GolezTrol
据我所了解,他们谈论的是持续时间,而不是日期时间。 - scragz
我喜欢Stack Overflow。谢谢大家。我甚至不确定哪一个是我最喜欢的。 - AJB
我用相同的测试数据运行了你的代码和我的代码,差异很明显。不过要注意,我并不是说我的代码就一定正确——因为我在解释需求时可能有些自己的理解。 - Peter Bailey
@Peter:唯一的两个问题是当您拥有非整数毫秒时间和非常大的秒时。但这基于上面的假设,即他有一个整数毫秒数。我想更好的解决方案取决于需求(我们只是在这里猜测)。 - ircmaxell
显示剩余5条评论

21

我的看法

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

1
我喜欢Stack Overflow。谢谢大家。我甚至不确定我最喜欢哪一个。 - AJB
我是一个 PHP 新手,我发现 @ircmaxell 的函数不能处理所有的值。在我的情况下,ms 值为:1189107。使用 ircmaxell 函数得到的结果约为 23 小时,而使用你的函数则为 00:19:49。 - zengr
@Peter Bailey - 我认为第6行应该写成:if ( $seconds >= 3600 ) - 即如果$seconds大于等于3600。这将确保恰好输出1小时 - 即3600秒,作为 01:00:00 而不是在没有此调整的情况下输出 00:00:00。感谢您提供的函数 - 我正在使用它来监控Drupal网站的一些性能日志记录。 - therobyouknow

3

我的代码不太易读,所以它肯定更好。 :p

基本上与@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);

2
如果您确实想使用日期函数来完成,那么您是正确的,但需要在外部处理毫秒,因为它仅基于秒级时间戳。
您可以按照以下方式操作:
<?
$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小时,您可能会将日期舍去。

在您的情况下,我认为您使用floor获取秒数的方法是正确的,然后您可以像这样使用模运算:

<?
$totalsecs = 86400*10;

$secs = $totalsecs%60;

echo "secs: $secs \n";

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

and so on..


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接