Question

I'm, getting this array from a youtube API request, but the duration format is very rare in my opinion. Why didn't they just throw seconds in there? In any case this is the array

[duration] => PT2M3S
[dimension] => 2d
[definition] => sd
[caption] => false

Is there a way to convert this duration to a "H:i:s" format in PHP?

Thanks in advance for your help

Was it helpful?

Solution 2

In fact it is simple ISO8601 date. Split string with regexp like (\d+) to minutes and seconds. Then get integer part of division of minutes by 60 to get hours. Get remainder of that division to get minutes.

here is an example that should work though i didn't tested it

preg_match_all('/(\d+)/',$youtube_time,$parts);

$hours = floor($parts[0][0]/60);
$minutes = $parts[0][0]%60;
$seconds = $parts[0][1];

OTHER TIPS

acidjazz has a great solution, but there is a typo where it displays the minutes. It should be $di->i for minutes, not $di->m. You can also remove the "public static" portion if you're not using it in an object, and I took out the sprintf().

Otherwise the function works as is:

function duration($ytDuration) {

    $di = new DateInterval($ytDuration);
    $string = '';

    if ($di->h > 0) {
      $string .= $di->h.':';
    }

    return $string.$di->i.':'.$di->s;
}

I would have added this as a comment to his answer, but there's the whole "You need 50 reputation to comment" BS that prevents me from sticking to the flow of this thread.

You can use php's DateInterval Class to parse it properly. For example a function in a youtube wrapper class to parse it to the format YouTube displays might look like:

  public static function duration($ytDuration) {

    $di = new DateInterval($ytDuration);
    $string = '';

    if ($di->h > 0) {
      $string .= $di->h.':';
    }

    return $string.$di->m.':'.sprintf('%02s',$di->s);
  }

I used @chris-z-s 's answer here , and converted it to php :

function getDurationSeconds($duration){
    preg_match_all('/[0-9]+[HMS]/',$duration,$matches);
    $duration=0;
    foreach($matches as $match){
        //echo '<br> ========= <br>';       
        //print_r($match);      
        foreach($match as $portion){        
            $unite=substr($portion,strlen($portion)-1);
            switch($unite){
                case 'H':{  
                    $duration +=    substr($portion,0,strlen($portion)-1)*60*60;            
                }break;             
                case 'M':{                  
                    $duration +=substr($portion,0,strlen($portion)-1)*60;           
                }break;             
                case 'S':{                  
                    $duration +=    substr($portion,0,strlen($portion)-1);          
                }break;
            }
        }
    //  echo '<br> duratrion : '.$duration;
    //echo '<br> ========= <br>';
    }
     return $duration;

}

it worked with me :)

May be it will be helpful for someone to get duration:

$interval = new \DateInterval($iso8601);

// in seconds:
$seconds = $interval->h * 360 + $interval->i * 60 + $interval->s;

// in "H:i:s" format:
echo $interval->format('%H:%i:%s');

this is my solution:

preg_match('/(\d+)H/', $duration, $match);
$h = ($match[0])?filter_var($match[0], FILTER_SANITIZE_NUMBER_INT).":":'';
preg_match('/(\d+)M/', $duration, $match);
$m = filter_var($match[0], FILTER_SANITIZE_NUMBER_INT).":";
preg_match('/(\d+)S/', $youtube_date, $match);
$s = filter_var($match[0], FILTER_SANITIZE_NUMBER_INT);
echo: "Duration: " . $h.$m.$s;

##:##:## Time format on PHP

 function NormalizeDuration($duration){
    preg_match('#PT(.*?)H(.*?)M(.*?)S#si',$duration,$out);
    if(empty($out[1])){
    preg_match('#PT(.*?)M(.*?)S#si',$duration,$out);
    if(empty($out[1])){
    preg_match('#PT(.*?)S#si',$duration,$out);
    if(empty($out[1])){
    return '00:00';
    }
    }else{
    if(strlen($out[1])==1){ $out[1]= '0'.$out[1]; }
    if(strlen($out[2])==1){ $out[2]= '0'.$out[2]; }
    return $out[1].':'.$out[2];
    }
    }else{
    if(strlen($out[1])==1){ $out[1]= '0'.$out[1]; }
    if(strlen($out[2])==1){ $out[2]= '0'.$out[2]; }
    if(strlen($out[3])==1){ $out[3]= '0'.$out[3]; }
    return $out[1].':'.$out[2].':'.$out[3];
    }
    }

Use the following php function will return the YouTube video duration..For more exciting codes follow this link more code samples

    function getYoutubeDuration($vid) 
    {
    $videoDetails =file_get_contents("https://www.googleapis.com/youtube/v3/videos?id=".$vid."&part=contentDetails&key=AIzaSyDen99uTRRPl9VT_Ra9eAisvZSc4aZDEns");
    $videoDetails =json_decode($videoDetails, true);
    foreach ($videoDetails['items'] as $vidTime)
     {
        $youtube_time = $vidTime['contentDetails']['duration'];
        preg_match_all('/(\d+)/',$youtube_time,$parts);
        $hours = (strlen(floor($parts[0][0]/60))<1)?floor($parts[0][0]/60):'0'.floor($parts[0][0]/60);
        $minutes = $parts[0][0]%60; (strlen($parts[0][0]%60)<1)?$parts[0][0]%60:'0'.$parts[0][0]%60;
        $seconds = $parts[0][1];(strlen($parts[0][1])<1)?$parts[0][1]:'0'.$parts[0][1];
        return $hours.":".$minutes.":".$seconds;
     }
    }

  echo getYoutubeDuration('J1lb3qJgfho');

As YouTube (Google) like to be difficult, they opt for non-standard formatting. So standard functions don't always work.

As such, I made this for my need's.

$length = $data['items'] ..... ['duration'];

$seconds = substr(stristr($length, 'S', true), -2, 2);
$seconds = preg_replace("/[^0-9]/", '', $seconds);
$minutes =  substr(stristr($length, 'M', true), -2, 2);
$minutes = preg_replace("/[^0-9]/", '', $minutes);
$hours =  substr(stristr($length, 'H', true), -2, 2);
$hours = preg_replace("/[^0-9]/", '', $hours);

Solution with named groups

PT((?P<hours>\d+)H)?((?P<minutes>\d+)M)?((?P<seconds>\d+)S)?

Examples can be found here https://regex101.com/r/wU3hT2/114

Python function:

def yt_time_to_seconds(time):
    regex_string = 'PT((?P<hours>\d+)H)?((?P<minutes>\d+)M)?((?P<seconds>\d+)S)?'
    regex = re.compile(regex_string)
    match = regex.match(time)
    if match:
        hours = int(match.group('hours'))
        minutes = int(match.group('minutes'))
        seconds = int(match.group('seconds'))
        return hours * 60 * 60 + minutes * 60 + seconds
    return 0

it worked perfectly for me 100%, only you should have \ DateInterval as root

function NormalizeDuration($duration){ //pass your time
    $start = new \DateTime('@0');
    $start->add(new \DateInterval($duration));

    return $start->format('H:i:s'); //format
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top