Как преобразовать продолжительность Youtube API V3 в Java

API Youtube V3 использует формат времени ISO8601 для описания продолжительности видео. Что-то похожее на "ПТ1М13С". И теперь я хочу преобразовать строку в количество секунд (например, в данном случае 73).

Есть ли какая-нибудь библиотека Java, которая может помочь мне легко выполнить задачу под Java 6? Или я должен выполнить задачу регулярного выражения самостоятельно?

Изменить

Наконец я принимаю ответ от @Joachim Sauer

Пример кода с Joda показан ниже.

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

System.out.println(s.getSeconds());

person Willy    schedule 29.05.2013    source источник
comment
Это дубликат? Этот вопрос касается формата даты.   -  person Willy    schedule 29.05.2013
comment
На самом деле не понимаю, как использовать SimpleDateFormat для получения количества секунд в этом случае, поскольку это не формат даты. Спасибо!   -  person Willy    schedule 29.05.2013
comment
@nhahtdh: это не дубликат, потому что связанный с ним обрабатывает строки даты, а это строка продолжительности!   -  person Joachim Sauer    schedule 29.05.2013


Ответы (14)


Joda Time – это библиотека для любых функций, связанных со временем.

Для этого конкретного случая ISOPeriodFormat. standard() возвращает PeriodFormatter, который может анализировать и форматировать этот формат.

В результате получается объект a Period (JavaDoc). Получение фактического количества секунд будет тогда period.toStandardSeconds().getSeconds(), но я предлагаю вам просто обрабатывать продолжительность как объект Period (для простоты обработки и безопасности типов).

Редактировать: примечание от меня из будущего: этому ответу уже несколько лет. Java 8 принесла java.time.Duration, который также может анализировать этот формат и не требует внешней библиотеки.

person Joachim Sauer    schedule 29.05.2013
comment
Благодарю вас! я сначала посмотрю - person Willy; 29.05.2013

Решение в Java 8:

Duration.parse(duration).getSeconds()
person Kamil    schedule 12.11.2014
comment
Вы должны убедиться, что для JAVA_HOME установлено значение JDK8 или что ваша среда IDE настроена на использование JDK8. Мне пришлось добавить плагин maven, чтобы приведенный выше код работал в моей IntelliJ IDEA 17. URL-адрес плагина: mvnrepository.com/artifact/org.apache.maven.plugins/ - person realPK; 24.07.2017
comment
в Android добавьте это в gradle: compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } (но оно доступно только для 26 API, поэтому в данный момент его использовать не рекомендуется) - person user924; 28.06.2018

Я могу опоздать на вечеринку, на самом деле это очень просто. Хотя могут быть и лучшие способы сделать это. продолжительность в миллисекундах.

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;
}
person Answer    schedule 17.05.2015

Вот мое решение

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

Он вернет строку в формате H:MM:SS, если вы хотите преобразовать в секундах, которые вы можете использовать

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

Примечание: он может генерировать исключение, поэтому обрабатывайте его в зависимости от размера result.split(":");

person Vikash Kumar Verma    schedule 27.12.2016
comment
Самое простое и лучшее решение этой проблемы в stackoverflow - person Karan Sharma; 28.07.2017
comment
обратите внимание, что это будет неточно, если пропущены часы H, M или S (например, PT35M10S или PT1H30S). нет гарантии появления H, M или S в поле - person Angel Koh; 12.11.2017

Может быть, это поможет кому-то, кто не хочет никакой библиотеки, кроме простой функции,

String duration="PT1H11M14S";

Это функция,

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;
}
person TechArcSri    schedule 29.01.2015

Вы можете использовать стандартный SimpleDateFormat, чтобы разобрать String на Date и обработать его оттуда:

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));
person kpentchev    schedule 29.05.2013
comment
Предупреждение: продолжительность - это не дата, и обращение с ней так, как будто она открывает большую банку с червями (подумайте о високосных годах, високосных секундах, часовых поясах и т. д.). - person Joachim Sauer; 29.05.2013
comment
Я согласен, но все же для простой задачи получения секунд из определенного формата это работает достаточно хорошо. - person kpentchev; 29.05.2013
comment
За исключением того, что формат может включать часы и не обязательно включать минуты (допустимы PT10S и PT1H1M1S в соответствии с ISO8601). - person Joachim Sauer; 29.05.2013
comment
Это стандартная проблема с реализацией Java SimpleDateFormat, которую снова можно легко решить, используя несколько экземпляров для случаев, когда часы и/или минуты отсутствуют. Я предлагаю не 100% решение, а отправную точку. Где связь с вашим предыдущим комментарием? - person kpentchev; 29.05.2013
comment
Да, но обход этой проблемы делает решение все более и более сложным, возможно, более сложным, чем написание правильного анализатора, и определенно более сложным, чем использование правильного анализатора. Я отвечал на ваш последний комментарий. - person Joachim Sauer; 29.05.2013
comment
Да, но он пропускает использование сторонних библиотек, что может быть преимуществом в некоторых ситуациях. - person kpentchev; 29.05.2013
comment
Благодарю вас! я сначала посмотрю - person Willy; 29.05.2013

Если вы можете быть уверены в правильности ввода и не можете использовать регулярное выражение, я использую этот код (возврат в миллисекундах):

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;
}
person Phil C    schedule 07.08.2014

Я реализовал этот метод, и он работал до сих пор.

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; 

}
person Othon Batista    schedule 30.03.2015

я сделал сам

Давай попробуем

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 ;
    }
}
person sonida    schedule 08.04.2015

И еще один долгий путь, чтобы сделать то же самое.

// 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;
    }
}
person user35603    schedule 28.04.2016

Я написал и использовал этот метод, чтобы получить фактическую продолжительность. Надеюсь это поможет.

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);
}
person Naveen T P    schedule 15.04.2018

Время уже отформатировано, так что кажется достаточно будет просто замены.

 private String stringForTime(String ytFormattedTime) {
                 return ytFormattedTime
                        .replace("PT","")
                        .replace("H",":")
                        .replace("M",":")
                        .replace("S","");
 }
person no_cola    schedule 29.03.2019

Используя этот веб-сайт:

// 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);
    }
  }
}
person Simon Arsenault    schedule 29.05.2013
comment
Эх, извините, но нет. Если вы настаиваете на использовании для этого регулярных выражений, то, по крайней мере, сделайте его тем, который на самом деле проверяет правильность ввода. Например, ваш код принимает 00, а также Dumdidledum1And a long story and some tex3asdf0. - person Joachim Sauer; 29.05.2013
comment
Лучше, но вы могли бы значительно упростить это: PT(\\d+)M\(\\d+\)S: нас интересуют только две числовые группы, и . на самом деле не следует использовать, так как PT1H3M также будет допустимым для ISO8601, но означает совсем другое (1 час + 3 минуты). - person Joachim Sauer; 29.05.2013
comment
Вы не пытались разобрать весь формат. Это может анализировать только пример OP и в реальном использовании приведет к серьезным ошибкам. Продолжительность видео может составлять от секунд до нескольких часов. - person nhahtdh; 29.05.2013

Вопрос Преобразование строки, совместимой с ISO 8601, в java.util.Date содержит другое решение:

Возможно, более простым решением является использование преобразователя типов данных в JAXB, поскольку JAXB должен иметь возможность анализировать строку даты ISO8601 в соответствии со спецификацией схемы XML. javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z") даст вам объект Calendar, и вы можете просто использовать на нем getTime(), если вам нужен объект Date.

person Matias Molinas    schedule 29.05.2013
comment
Этот вопрос касается формата длительности ISO8601, а не формата даты ISO8601. - person Joachim Sauer; 05.06.2013