How to convert Youtube API V3 duration in Java
Asked Answered
S

15

21

The Youtube V3 API uses ISO8601 time format to describe the duration of videos. Something likes "PT1M13S". And now I want to convert the string to the number of seconds (for example 73 in this case).

Is there any Java library can help me easily do the task under Java 6? Or I have to do the regex task by myself?

Edit

Finally I accept the answer from @Joachim Sauer

The sample code with Joda is as below.

PeriodFormatter formatter = ISOPeriodFormat.standard();
Period p = formatter.parsePeriod("PT1H1M13S");
Seconds s = p.toStandardSeconds();

System.out.println(s.getSeconds());
Sidetrack answered 29/5, 2013 at 11:23 Comment(3)
Is it duplicate? That question is for date-format.Sidetrack
Really not understand how to use SimpleDateFormat to get the number of seconds in this case as it is not a date format. Thanks!Sidetrack
@nhahtdh: it's not a duplicate, because the linked-to one handles date strings, while this is a duration string!Cockeye
C
15

Joda Time is the go-to library for time-related functions of any kind.

For this specific case ISOPeriodFormat.standard() returns a PeriodFormatter that can parse and format that format.

The resulting object is a Period (JavaDoc). Getting the actual number of seconds would then be period.toStandardSeconds().getSeconds(), but I suggest you just handle the duration as a Period object (for ease of handling and for type safety).

Edit: a note from future me: this answer is several years old now. Java 8 brought java.time.Duration along which can also parse this format and doesn't require an external library.

Cockeye answered 29/5, 2013 at 11:46 Comment(1)
Thank you! I take a look firstSidetrack
C
14

Solution in Java 8:

Duration.parse(duration).getSeconds()
Copenhaver answered 12/11, 2014 at 9:55 Comment(2)
You have to make sure your JAVA_HOME is set to JDK8 or your IDE is configured to use JDK8. I had to add maven plugin to make above code work in my IntelliJ IDEA 17. Plugin URL: mvnrepository.com/artifact/org.apache.maven.plugins/…Vaclava
in Android add this to gradle: compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } (but it's available only for 26 API, so it's not recommended to use it at this moment)Oldline
C
13

I may be late for the party, it's actually very simple. Although there may be better ways of doing this. duration is in milliseconds.

public long getDuration() {
    String time = "PT15H12M46S".substring(2);
    long duration = 0L;
    Object[][] indexs = new Object[][]{{"H", 3600}, {"M", 60}, {"S", 1}};
    for(int i = 0; i < indexs.length; i++) {
        int index = time.indexOf((String) indexs[i][0]);
        if(index != -1) {
            String value = time.substring(0, index);
            duration += Integer.parseInt(value) * (int) indexs[i][1] * 1000;
            time = time.substring(value.length() + 1);
        }
    }
    return duration;
}
Centroclinal answered 17/5, 2015 at 5:44 Comment(0)
T
3

Here is my solution

public class MyDateFromat{
    public static void main(String args[]){
        String ytdate = "PT1H1M15S";
        String result = ytdate.replace("PT","").replace("H",":").replace("M",":").replace("S","");
        String arr[]=result.split(":");
        String timeString = String.format("%d:%02d:%02d", Integer.parseInt(arr[0]), Integer.parseInt(arr[1]),Integer.parseInt(arr[2]));
        System.out.print(timeString);       
    }
}

It will return a string in H:MM:SS format if you want to convert in seconds you can use

int timeInSedonds = int timeInSecond = Integer.parseInt(arr[0])*3600 + Integer.parseInt(arr[1])*60 +Integer.parseInt(arr[2])

Note: it can throw exception so please handle it based on size of result.split(":");

Throve answered 27/12, 2016 at 9:1 Comment(2)
Easiest and best solution on stackoverflow for this problemLotson
note that this will be in accurate for time missing H, M or S (e.g. PT35M10S or PT1H30S). there is no guarantee of H, M or S appearing in the fieldMario
I
1

May be this would help some one who don't want any library but a simple function,

String duration="PT1H11M14S";

This is the function,

private String getTimeFromString(String duration) {
    // TODO Auto-generated method stub
    String time = "";
    boolean hourexists = false, minutesexists = false, secondsexists = false;
    if (duration.contains("H"))
        hourexists = true;
    if (duration.contains("M"))
        minutesexists = true;
    if (duration.contains("S"))
        secondsexists = true;
    if (hourexists) {
        String hour = "";
        hour = duration.substring(duration.indexOf("T") + 1,
                duration.indexOf("H"));
        if (hour.length() == 1)
            hour = "0" + hour;
        time += hour + ":";
    }
    if (minutesexists) {
        String minutes = "";
        if (hourexists)
            minutes = duration.substring(duration.indexOf("H") + 1,
                    duration.indexOf("M"));
        else
            minutes = duration.substring(duration.indexOf("T") + 1,
                    duration.indexOf("M"));
        if (minutes.length() == 1)
            minutes = "0" + minutes;
        time += minutes + ":";
    } else {
        time += "00:";
    }
    if (secondsexists) {
        String seconds = "";
        if (hourexists) {
            if (minutesexists)
                seconds = duration.substring(duration.indexOf("M") + 1,
                        duration.indexOf("S"));
            else
                seconds = duration.substring(duration.indexOf("H") + 1,
                        duration.indexOf("S"));
        } else if (minutesexists)
            seconds = duration.substring(duration.indexOf("M") + 1,
                    duration.indexOf("S"));
        else
            seconds = duration.substring(duration.indexOf("T") + 1,
                    duration.indexOf("S"));
        if (seconds.length() == 1)
            seconds = "0" + seconds;
        time += seconds;
    }
    return time;
}
Ivelisseivens answered 29/1, 2015 at 13:34 Comment(0)
M
0

You can use the standart SimpleDateFormat to parse the String to a Date and process it from there:

DateFormat df = new SimpleDateFormat("'PT'mm'M'ss'S'");
String youtubeDuration = "PT1M13S";
Date d = df.parse(youtubeDuration);
Calendar c = new GregorianCalendar();
c.setTime(d);
c.setTimeZone(TimeZone.getDefault());
System.out.println(c.get(Calendar.MINUTE));
System.out.println(c.get(Calendar.SECOND));
Mithridate answered 29/5, 2013 at 12:10 Comment(7)
Warning: a duration is not a date, and treating it like one opens a big can of worms (think leap years, leap seconds, timezones, ...).Cockeye
I agree, but still for the simple task of getting the seconds out of the defined format it works well enough.Mithridate
Except that the format could include hours, and doesn't necessarily include minutes (PT10S and PT1H1M1S would be valid, according to ISO8601).Cockeye
This is a standard issue with the Java SimpleDateFormat implementation, which can again be easily solved by using several instances for the cases where there are/aren't any hours and/or minutes. I am not providing a 100% solution but a starting point. Where is the connection to your previous comment?Mithridate
Yes, but working around this problem makes the solution more and more complex, probably more complex than writing a proper parser and definitely more complex than using a proper parser. I was responding to your last comment.Cockeye
Yes, but it skips the usage of 3rd-party libs, which might be a benefit in some situations.Mithridate
Thank you! I take a look firstSidetrack
J
0

In case you can be pretty sure about the validity of the input and can't use regex, I use this code (returns in miliseconds):

Integer parseYTDuration(char[] dStr) {
    Integer d = 0;

    for (int i = 0; i < dStr.length; i++) {
        if (Character.isDigit(dStr[i])) {
            String digitStr = "";
            digitStr += dStr[i];
            i++;
            while (Character.isDigit(dStr[i])) {
                digitStr += dStr[i];
                i++;
            }

            Integer digit = Integer.valueOf(digitStr);

            if (dStr[i] == 'H')
                d += digit * 3600;
            else if (dStr[i] == 'M')
                d += digit * 60;
            else
                d += digit;
        }
    }

    return d * 1000;
}
Jenn answered 7/8, 2014 at 9:19 Comment(0)
P
0

I've implemented this method and it has worked so far.

private String timeHumanReadable (String youtubeTimeFormat) {
// Gets a PThhHmmMssS time and returns a hh:mm:ss time

    String
            temp = "",
            hour = "",
            minute = "",
            second = "",
            returnString;

    // Starts in position 2 to ignore P and T characters
    for (int i = 2; i < youtubeTimeFormat.length(); ++ i)
    {
        // Put current char in c
        char c = youtubeTimeFormat.charAt(i);

        // Put number in temp
        if (c >= '0' && c <= '9')
            temp = temp + c;
        else
        {
            // Test char after number
            switch (c)
            {
                case 'H' : // Deal with hours
                    // Puts a zero in the left if only one digit is found
                    if (temp.length() == 1) temp = "0" + temp;

                    // This is hours
                    hour = temp;

                    break;

                case 'M' : // Deal with minutes
                    // Puts a zero in the left if only one digit is found
                    if (temp.length() == 1) temp = "0" + temp;

                    // This is minutes
                    minute = temp;

                    break;

                case  'S': // Deal with seconds
                    // Puts a zero in the left if only one digit is found
                    if (temp.length() == 1) temp = "0" + temp;

                    // This is seconds
                    second = temp;

                    break;

            } // switch (c)

            // Restarts temp for the eventual next number
            temp = "";

        } // else

    } // for

    if (hour == "" && minute == "") // Only seconds
        returnString = second;
    else {
        if (hour == "") // Minutes and seconds
            returnString = minute + ":" + second;
        else // Hours, minutes and seconds
            returnString = hour + ":" + minute + ":" + second;
    }

    // Returns a string in hh:mm:ss format
    return returnString; 

}
Paisa answered 30/3, 2015 at 1:5 Comment(0)
G
0

I did by myself

Let's try

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.

public class YouTubeDurationUtils {
    /**
     * 
     * @param duration
     * @return "01:02:30"
     */
    public static String convertYouTubeDuration(String duration) {
        String youtubeDuration = duration; //"PT1H2M30S"; // "PT1M13S";
        Calendar c = new GregorianCalendar();
        try {
            DateFormat df = new SimpleDateFormat("'PT'mm'M'ss'S'");
            Date d = df.parse(youtubeDuration);
            c.setTime(d);
        } catch (ParseException e) {
            try {
                DateFormat df = new SimpleDateFormat("'PT'hh'H'mm'M'ss'S'");
                Date d = df.parse(youtubeDuration);
                c.setTime(d);
            } catch (ParseException e1) {
                try {
                    DateFormat df = new SimpleDateFormat("'PT'ss'S'");
                    Date d = df.parse(youtubeDuration);
                    c.setTime(d);
                } catch (ParseException e2) {
                }
            }
        }
        c.setTimeZone(TimeZone.getDefault());

        String time = "";
        if ( c.get(Calendar.HOUR) > 0 ) {
            if ( String.valueOf(c.get(Calendar.HOUR)).length() == 1 ) {
                time += "0" + c.get(Calendar.HOUR);
            }
            else {
                time += c.get(Calendar.HOUR);
            }
            time += ":";
        }
        // test minute
        if ( String.valueOf(c.get(Calendar.MINUTE)).length() == 1 ) {
            time += "0" + c.get(Calendar.MINUTE);
        }
        else {
            time += c.get(Calendar.MINUTE);
        }
        time += ":";
        // test second
        if ( String.valueOf(c.get(Calendar.SECOND)).length() == 1 ) {
            time += "0" + c.get(Calendar.SECOND);
        }
        else {
            time += c.get(Calendar.SECOND);
        }
        return time ;
    }
}
Gorged answered 8/4, 2015 at 18:3 Comment(0)
P
0

And yet another long way to do the same.

// PT1H9M24S -->  1:09:24
// PT2H1S"   -->  2:00:01
// PT23M2S   -->  23:02
// PT31S     -->  0:31

public String convertDuration(String duration) {
    duration = duration.substring(2);  // del. PT-symbols
    String H, M, S;
    // Get Hours:
    int indOfH = duration.indexOf("H");  // position of H-symbol
    if (indOfH > -1) {  // there is H-symbol
        H = duration.substring(0,indOfH);      // take number for hours
        duration = duration.substring(indOfH); // del. hours
        duration = duration.replace("H","");   // del. H-symbol
    } else {
        H = "";
    }
    // Get Minutes:
    int indOfM = duration.indexOf("M");  // position of M-symbol
    if (indOfM > -1) {  // there is M-symbol
        M = duration.substring(0,indOfM);      // take number for minutes
        duration = duration.substring(indOfM); // del. minutes
        duration = duration.replace("M","");   // del. M-symbol
        // If there was H-symbol and less than 10 minutes
        // then add left "0" to the minutes
        if (H.length() > 0 && M.length() == 1) {
            M = "0" + M;
        }
    } else {
        // If there was H-symbol then set "00" for the minutes
        // otherwise set "0"
        if (H.length() > 0) {
            M = "00";
        } else {
            M = "0";
        }
    }
    // Get Seconds:
    int indOfS = duration.indexOf("S");  // position of S-symbol
    if (indOfS > -1) {  // there is S-symbol
        S = duration.substring(0,indOfS);      // take number for seconds
        duration = duration.substring(indOfS); // del. seconds
        duration = duration.replace("S","");   // del. S-symbol
        if (S.length() == 1) {
            S = "0" + S;
        }
    } else {
        S = "00";
    }
    if (H.length() > 0) {
        return H + ":" +  M + ":" + S;
    } else {
        return M + ":" + S;
    }
}
Patio answered 28/4, 2016 at 7:37 Comment(0)
R
0

I have written and used this method to get the actual duration. Hope this helps.

private String parseDuration(String duration) {
    duration = duration.contains("PT") ? duration.replace("PT", "") : duration;
    duration = duration.contains("S") ? duration.replace("S", "") : duration;
    duration = duration.contains("H") ? duration.replace("H", ":") : duration;
    duration = duration.contains("M") ? duration.replace("M", ":") : duration;
    String[] split = duration.split(":");
    for(int i = 0; i< split.length; i++){
        String item = split[i];
        split[i] = item.length() <= 1 ? "0"+item : item;
    }
    return TextUtils.join(":", split);
}
Rudolph answered 15/4, 2018 at 18:11 Comment(0)
A
0

Time is already formatted, so it seems just replacing will be enough.

 private String stringForTime(String ytFormattedTime) {
                 return ytFormattedTime
                        .replace("PT","")
                        .replace("H",":")
                        .replace("M",":")
                        .replace("S","");
 }
Autarky answered 29/3, 2019 at 11:2 Comment(0)
R
0
public String pretty(String duration) {
  String time = duration.replace("PT", "");
  String hour = null;
  String minute = null;
  String second = null;

  if (time.indexOf("H") > 0) {
    String[] split = time.split("H");
    if (split.length > 0) {
      hour = split[0];
    }
    if (split.length > 1) {
      time = split[1];
    }
  }

  if (time.indexOf("M") > 0) {
    String[] split = time.split("M");
    if (split.length > 0) {
      minute = split[0];
    }
    if (split.length > 1) {
      time = split[1];
    }
  }

  if (time.indexOf("S") > 0) {
    String[] split = time.split("S");
    if (split.length > 0) {
      second = split[0];
    }
  }

  if (TextUtils.isEmpty(hour)) {
    if (TextUtils.isEmpty(minute)) { return "0:" + pad(second, 2, '0'); }
    else { return minute + ":" + pad(second, 2, '0'); }
  }
  else {
    if (TextUtils.isEmpty(minute)) { return hour + ":00:" + pad(second, 2, '0'); }
    else {return hour + ":" + pad(minute, 2, '0') + ":" + pad(second, 2, '0');}
  }
}

private String pad(String word, int length, char ch) {
  if (TextUtils.isEmpty(word)) { word = ""; }
  return length > word.length() ? pad(ch + word, length, ch) : word;
}
Recce answered 7/7, 2020 at 11:56 Comment(0)
S
-1

Using this website:

// URL that generated this code:
// http://txt2re.com/index-java.php3?s=PT1M13S&6&3&18&20&-19&-21 

import java.util.regex.*;

class Main
{
  public static void main(String[] args)
  {
    String txt="PT1M13S";

    String re1="(P)";   // Any Single Character 1
    String re2="(T)";   // Any Single Character 2
    String re3="(\\d+)";    // Integer Number 1
    String re4="(M)";   // Any Single Character 3
    String re5="(\\d+)";    // Integer Number 2
    String re6="(S)";   // Any Single Character 4

    Pattern p = Pattern.compile(re1+re2+re3+re4+re5+re6,Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
    Matcher m = p.matcher(txt);
    if (m.find())
    {
        String c1=m.group(1);
        String c2=m.group(2);
        String minutes=m.group(3); // Minutes are here
        String c3=m.group(4);
        String seconds=m.group(5); // Seconds are here
        String c4=m.group(6);
        System.out.print("("+c1.toString()+")"+"("+c2.toString()+")"+"("+minutes.toString()+")"+"("+c3.toString()+")"+"("+seconds.toString()+")"+"("+c4.toString()+")"+"\n");

        int totalSeconds = Integer.parseInt(minutes) * 60 + Integer.parseInt(seconds);
    }
  }
}
Segura answered 29/5, 2013 at 11:51 Comment(3)
Ugh, sorry, but no. If you insist on using regular expressions for this, then at least make it one that actually checks if the input is even remotely well-formed. For example your code accepts 00 as well as Dumdidledum1And a long story and some tex3asdf0.Cockeye
Better, but you could simplify that a lot: PT(\\d+)M\(\\d+\)S: We only care about the two numeric groups and the . should really not be used, as PT1H3M would also be valid ISO8601, but mean something else entirely (1 hour + 3 minutes).Cockeye
You didn't attempt to parse the whole format. This can only parses OP's example, and is going to fail badly in actual usage. Duration of a video can be as short as seconds, and can be as long as a few hours.Deviltry
A
-1

The question Converting ISO 8601-compliant String to java.util.Date contains another solution:

The easier solution is possibly to use the data type converter in JAXB, since JAXB must be able to parse ISO8601 date string according to the XML Schema specification. javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z") will give you a Calendar object and you can simply use getTime() on it, if you need a Date object.

Arber answered 29/5, 2013 at 14:46 Comment(1)
This question is about the ISO8601 duration format and not about the ISO8601 date format.Cockeye

© 2022 - 2025 — McMap. All rights reserved.