How to convert YouTube API duration (ISO 8601 duration in the format PT#M#S) to seconds
Asked Answered
R

6

18

How can I manipulate a date time in the format PT#M#S with JavaScript?

for example: PT5M33S

I'd like to output as hh:mm:ss.

Rimrock answered 27/9, 2013 at 23:1 Comment(4)
Fiddle: jsfiddle.net/Daugilas/kbeb0p99/1Correll
@Daugilas Kakaras Very nice! But you need to update function. When format like P1D - (one day) function doesn't works.Xenocrates
@Serhiog.Lazin, true - updated: jsfiddle.net/kbeb0p99/4 *after quite a long time :)Correll
this should work gist.github.com/Fauntleroy/5167736Decani
P
27

Here's the basic code to get total number of seconds and other parts. I feel uneasy doing this, as the rule says that any time you want to date logic you shouldn't :) But anyways, here it goes - Google made it not easy, providing total seconds in the getduration player API, and providing totally different format in the gdata api.

var reptms = /^PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?$/;
var hours = 0, minutes = 0, seconds = 0, totalseconds;

if (reptms.test(input)) {
  var matches = reptms.exec(input);
  if (matches[1]) hours = Number(matches[1]);
  if (matches[2]) minutes = Number(matches[2]);
  if (matches[3]) seconds = Number(matches[3]);
  totalseconds = hours * 3600  + minutes * 60 + seconds;
}
Perturbation answered 31/3, 2014 at 13:4 Comment(3)
thanks, With a little bit of tweaks I made it work just as I needed.Hilleary
How about duration: "PT26M"Beverlybevers
Input formats can also contain decimals. e.g. PT36.53S. Here's and updated regex : ^PT(?:(\d+\.*\d*)H)?(?:(\d+\.*\d*)M)?(?:(\d+\.*\d*)S)?$Librate
L
5

Here is how you can get a youtube video data via Youtube API (v3) in a simple way and convert the video duration (ISO 8601) to seconds. Don't forget to change the { YOUR VIDEO ID } and { YOUR KEY } attribute in URL to your video id and your public google key. You can create a public key accessing the google developer console.

  $.ajax({
       url: "https://www.googleapis.com/youtube/v3/videos?id={ YOUR VIDEO ID }&part=contentDetails&key={ YOUR KEY }",
       dataType: "jsonp",
       success: function (data) { youtubeCallback (data); }
  });

    function youtubeCallback(data) {

        var duration = data.items[0].contentDetails.duration;
        alert ( convertISO8601ToSeconds (duration) );
    }        

    function convertISO8601ToSeconds(input) {

        var reptms = /^PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?$/;
        var hours = 0, minutes = 0, seconds = 0, totalseconds;

        if (reptms.test(input)) {
            var matches = reptms.exec(input);
            if (matches[1]) hours = Number(matches[1]);
            if (matches[2]) minutes = Number(matches[2]);
            if (matches[3]) seconds = Number(matches[3]);
            totalseconds = hours * 3600  + minutes * 60 + seconds;
        }

        return (totalseconds);
    }
Luxuriate answered 4/6, 2015 at 16:52 Comment(1)
How about duration: "PT26M"Beverlybevers
W
1

While these answers are technically correct; you should check out momentjs if you plan to do a lot of with time and durations. Also check out moment-duration-formats which makes formatting durations just as simple as regular momentjs time

An example of how easy these 2 modules make this

moment.duration('PT5M33S').format('hh:mm:ss')

that will output 05:33. And there's plenty of other uses.

Though there's a reason youtube uses ISO8601 format since it's a standard, so keep that in mind.

Woolly answered 26/11, 2017 at 17:59 Comment(4)
TypeError: moment.duration(...).format is not a function I am getting this with Node 8.10 , moment 2.22.2Butterfly
@Butterfly Did you install the moment-duration-format package & require it?Woolly
I used like this: moment().day("Monday").year(year_val).week(week_val).format('YYYY-MM-DD') and it is working.Butterfly
@Butterfly so you didn't read the documentation for the packages? Alright.Woolly
U
1

At the 'moment' in 2023 Moment.js is in legacy mode.

You can use the Duration class of Luxon.js (an offspring of Moment.js) to parse ISO8601 durations.

import { Duration } from 'luxon'

// OP's desired hh:mm:ss format
> Duration.fromISO('PT20S').toISOTime({suppressMilliseconds: true})
'00:00:20'


// other useful outputs

> Duration.fromISO('PT2M42S').toHuman()
'2 minutes, 42 seconds'

> Duration.fromISO('PT1H16M5S').toMillis()
4565000

> Duration.fromISO('P1DT2H1S').toObject()
{ days: 1, hours: 2, seconds: 1 }
Unalienable answered 15/3, 2023 at 13:29 Comment(0)
L
0

I approuched this by checking the character two indices to the left of the unit (H,M,S) and checking if it is a number, if not the unit is single digit and I prepend an extra '0'. Otherwise I return the two digit number.

   function formatTimeUnit(input, unit){
     var index = input.indexOf(unit);
     var output = "00"
    if(index < 0){
      return output; // unit isn't in the input
    }

    if(isNaN(input.charAt(index-2))){
      return '0' + input.charAt(index-1);
    }else{
      return input.charAt(index-2) + input.charAt(index-1);
    }
  }

I do this for hours, minutes and seconds. I also drop hours if there aren't any in the input, this is ofcourse optional.

    function ISO8601toDuration(input){
     var H = formatTimeUnit(input, 'H');
     var M = formatTimeUnit(input, 'M');
     var S = formatTimeUnit(input, 'S');

    if(H == "00"){
      H = "";
    }else{
      H += ":"
    }

    return H  + M + ':' + S ;
  }

then just call it like this

  duration = ISO8601toDuration(item.duration);

I use this to format youtube data API video durations. Hope this helps somebody

Leveridge answered 5/9, 2018 at 16:29 Comment(0)
D
0

The simplest way is to use moment-duration-formats. Still, below is a custom function to convert the YouTube API duration response to hh:mm:ss format.

const convertISO8601ToStringWithColons = string => {
        let hours, minutes, seconds;

        if (string.includes("H")) {
            hours = string.slice(2, string.indexOf("H"));
        } else {
            hours = false;
        }

        if (string.includes("S")) {
            // checks if number is one-digit and inserts 0 in front of it
            if (isNaN(parseInt(string.charAt(string.indexOf("S") - 2)))) {
                seconds = "0" + string.charAt(string.indexOf("S") - 1)
            } else {
                seconds = string.slice(-3, -1)
            }
        } else {
            seconds = "00"
        }
        
        // determines how minutes are displayed, based on existence of hours and minutes
        if (hours) {
            if (string.includes("M")) {
                if (string.indexOf("M") - string.indexOf("H") === 3) {
                    minutes = string.slice(string.indexOf("H") + 1, string.indexOf("M"))
                } else {
                    minutes = "0" + string.charAt(string.indexOf("M") - 1)
                }
            } else {
                minutes = "00"
            }
        } else {
            if (string.includes("M")) {
                minutes = string.slice(2, (string.indexOf("M")))
            } else {
                minutes = "0"
            }   
        }

        // distinction because livestreams (P0D) are not considered
        return string === "P0D" ? "Live" : `${hours ? hours + ":" : ""}${minutes}:${seconds}`
    }
    
const textExamples = ["PT11H57M30S", "PT7H2M", "PT10H37S", "PT8H", "PT4M58S", "PT39M", "PT7S", "P0D"]
textExamples.forEach(element => {
    console.log(convertISO8601ToStringWithColons(element))
});
Dives answered 26/7, 2022 at 13:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.