web-dev-qa-db-fra.com

Conversion du format de durée de la vidéo Youtube Data API V3 en secondes dans JavaScript/Node.js

J'essaie de convertir la chaîne ISO 8601 en secondes dans JS/Node. Le mieux que j'ai pu trouver était:

function convert_time(duration) {
    var a = duration.match(/\d+/g)
    var duration = 0

    if(a.length == 3) {
        duration = duration + parseInt(a[0]) * 3600;
        duration = duration + parseInt(a[1]) * 60;
        duration = duration + parseInt(a[2]);
    }

    if(a.length == 2) {
        duration = duration + parseInt(a[0]) * 60;
        duration = duration + parseInt(a[1]);
    }

    if(a.length == 1) {
        duration = duration + parseInt(a[0]);
    }
    return duration
}

Cela fonctionne lorsque je saisis des chaînes telles que "PT48S", "PT3M20S" ou "PT3H2M31S", mais échoue lamentablement si la chaîne est "PT1H11S". Quelqu'un a-t-il une meilleure idée?

23
Andrus Asumets

Je suggère ce petit bidouillage pour prévenir votre cas problématique:

function convert_time(duration) {
    var a = duration.match(/\d+/g);

    if (duration.indexOf('M') >= 0 && duration.indexOf('H') == -1 && duration.indexOf('S') == -1) {
        a = [0, a[0], 0];
    }

    if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1) {
        a = [a[0], 0, a[1]];
    }
    if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1 && duration.indexOf('S') == -1) {
        a = [a[0], 0, 0];
    }

    duration = 0;

    if (a.length == 3) {
        duration = duration + parseInt(a[0]) * 3600;
        duration = duration + parseInt(a[1]) * 60;
        duration = duration + parseInt(a[2]);
    }

    if (a.length == 2) {
        duration = duration + parseInt(a[0]) * 60;
        duration = duration + parseInt(a[1]);
    }

    if (a.length == 1) {
        duration = duration + parseInt(a[0]);
    }
    return duration
}

Fiddle

21
Paul Rad
function YTDurationToSeconds(duration) {
  var match = duration.match(/PT(\d+H)?(\d+M)?(\d+S)?/);

  match = match.slice(1).map(function(x) {
    if (x != null) {
        return x.replace(/\D/, '');
    }
  });

  var hours = (parseInt(match[0]) || 0);
  var minutes = (parseInt(match[1]) || 0);
  var seconds = (parseInt(match[2]) || 0);

  return hours * 3600 + minutes * 60 + seconds;
}

fonctionne pour ces cas:

PT1H
PT23M
PT45S
PT1H23M
PT1H45S
PT23M45S
PT1H23M45S
23
redgetan

Si vous utilisez moment.js vous pouvez simplement appeler ...

moment.duration('PT15M33S').asMilliseconds();

= 933000 ms

23
Mulhoon

Voici ma solution:

function parseDuration(duration) {
    var matches = duration.match(/[0-9]+[HMS]/g);

    var seconds = 0;

    matches.forEach(function (part) {
        var unit = part.charAt(part.length-1);
        var amount = parseInt(part.slice(0,-1));

        switch (unit) {
            case 'H':
                seconds += amount*60*60;
                break;
            case 'M':
                seconds += amount*60;
                break;
            case 'S':
                seconds += amount;
                break;
            default:
                // noop
        }
    });

    return seconds;
}
8
Chris Z-S

Ma solution:

function convert_time(duration) {
  var total = 0;
  var hours = duration.match(/(\d+)H/);
  var minutes = duration.match(/(\d+)M/);
  var seconds = duration.match(/(\d+)S/);
  if (hours) total += parseInt(hours[1]) * 3600;
  if (minutes) total += parseInt(minutes[1]) * 60;
  if (seconds) total += parseInt(seconds[1]);
  return total;
}

Fiddle

2
John

J'ai écrit une variante de CoffeeScript (vous pouvez facilement la compiler sur coffeescript.org lorsque vous le souhaitez)

DIFFERENCE: la durée de retour est dans un format lisible par l’homme (par exemple, 04:20, 01:05:48)

String.prototype.parseDuration = ->
    m = @.match /[0-9]+[HMS]/g
    res = ""
    fS = fM = !1
    for part in m
        unit = part.slice -1
        val = part.slice 0, part.length - 1
        switch unit
            when "H" then res += val.zeros( 2 ) + ":"
            when "M"
                fM = 1
                res += val.zeros( 2 ) + ":"
            when "S"
                fS = 1
                res += if fM then val.zeros 2 else "00:" + val.zeros 2

     if !fS then res += "00"
     res

J'ai également implémenté cette fonction d'assistance pour renseigner <10 valeurs avec un zéro non significatif:

String.prototype.zeros = ( x ) ->
    len = @length
    if !x or len >= x then return @
    zeros = ""
    zeros += "0" for [0..(x-len-1)]
    zeros + @

3nj0y !!!

1
faeb187

Vous pouvez trouver une solution très simple PHP ici - Comment convertir le temps de l'API Youtube (durée de la vidéo en chaîne ISO 8601) en secondes PHP - Code

Cette fonction convert_time () prend un paramètre en entrée - le temps de l'API Youtube (durée de la vidéo) au format de chaîne ISO 8601 et renvoie sa durée en secondes.

function convert_time($str) 
{
    $n = strlen($str);
    $ans = 0;
    $curr = 0;
    for($i=0; $i<$n; $i++)
    {
        if($str[$i] == 'P' || $str[$i] == 'T')
        {

        }
        else if($str[$i] == 'H')
        {
            $ans = $ans + 3600*$curr;
            $curr = 0;
        }
        else if($str[$i] == 'M')
        {
            $ans = $ans + 60*$curr;
            $curr = 0;
        }
        else if($str[$i] == 'S')
        {
            $ans = $ans + $curr;
            $curr = 0;
        }
        else
        {
            $curr = 10*$curr + $str[$i];
        }
    }
    return($ans);
}

Test de certaines entrées: 

"PT2M23S" => 143
"PT2M" => 120
"PT28S" => 28
"PT5H22M31S" => 19351
"PT3H" => 10800
"PT1H6M" => 3660
"PT1H6S" => 3606
1

Ce n'est pas spécifique à Java, mais je voudrais ajouter un extrait de code Java car cela peut être utile pour d'autres utilisateurs

String duration = "PT1H23M45S";
Pattern pattern = Pattern.compile("PT(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?");
Matcher matcher = pattern.matcher(duration);
long sec = 0;
long min = 0;
long hour = 0;
if (matcher.find())
{
    if(matcher.group(1)!=null)
        hour = NumberUtils.toInt(matcher.group(1));
    if(matcher.group(2)!=null)
        min = NumberUtils.toInt(matcher.group(2));
    if(matcher.group(3)!=null)
        sec = NumberUtils.toInt(matcher.group(3));

}
long totalSec = (hour*3600)+(min*60)+sec;
System.out.println(totalSec);
0

Voici la solution de @redgetan dans ES6.

Je l'ai aussi réparé pendant des années, des semaines et des jours.

https://www.digi.com/resources/documentation/digidocs/90001437-13/reference/r_iso_8601_duration_format.htm

// Copied from:
// https://stackoverflow.com/questions/22148885/converting-youtube-data-api-v3-video-duration-format-to-seconds-in-javascript-no
function parseISO8601Duration(duration) {
    const match = duration.match(/P(\d+Y)?(\d+W)?(\d+D)?T(\d+H)?(\d+M)?(\d+S)?/)
    // An invalid case won't crash the app.
    if (!match) {
        console.error(`Invalid YouTube video duration: ${duration}`)
        return 0
    }
    const [
        years,
        weeks,
        days,
        hours,
        minutes,
        seconds
    ] = match.slice(1).map(_ => _ ? parseInt(_.replace(/\D/, '')) : 0)
  return (((years * 365 + weeks * 7 + days) * 24 + hours) * 60 + minutes) * 60 + seconds
}

if (parseISO8601Duration('PT1H') !== 3600) {
    throw new Error()
}

if (parseISO8601Duration('PT23M') !== 1380) {
    throw new Error()
}

if (parseISO8601Duration('PT45S') !== 45) {
    throw new Error()
}

if (parseISO8601Duration('PT1H23M') !== 4980) {
    throw new Error()
}

if (parseISO8601Duration('PT1H45S') !== 3645) {
    throw new Error()
}

if (parseISO8601Duration('PT1H23M45S') !== 5025) {
    throw new Error()
}

if (parseISO8601Duration('P43W5DT5M54S') !== 26438754) {
    throw new Error()
}

if (parseISO8601Duration('P1Y43W5DT5M54S') !== 57974754) {
    throw new Error()
}
0
asdfasdfads

En supposant que l'entrée soit valide, nous pouvons utiliser la méthode regex exec pour effectuer une itération sur la chaîne et extraire le groupe de manière séquentielle:

const YOUTUBE_TIME_RE = /(\d+)([HMS])/g;
const YOUTUBE_TIME_UNITS = {
    'H': 3600,
    'M': 60,
    'S': 1
}

/**
 * Returns the # of seconds in a youtube time string
 */
function parseYoutubeDate(date: string): number {
    let ret = 0;
    let match: RegExpExecArray;
    while (match = YOUTUBE_TIME_RE.exec(date)) {
        ret += (YOUTUBE_TIME_UNITS[match[2]]) * Number(match[1]);
    }
    return ret;
}
0
dfl

Je réalise que eval est impopulaire, mais voici l'approche la plus facile et la plus rapide que je puisse imaginer. Prendre plaisir.

function formatDuration(x) {
   return eval(x.replace('PT','').replace('H','*3600+').replace('M','*60+').replace('S', '+').slice(0, -1));
}
0
chad steele

J'ai rencontré des problèmes avec la solution ci-dessus. J'ai décidé de l'écrire aussi obtus que possible. J'utilise aussi mon propre "getIntValue" à la place de parseInt pour plus de santé mentale.

Juste pensé que d'autres recherches pourraient apprécier la mise à jour.

Fiddle

    function convertYouTubeTimeFormatToSeconds(timeFormat) {

    if ( timeFormat === null || timeFormat.indexOf("PT") !== 0 ) {
        return 0;
    }

    // match the digits into an array
    // each set of digits into an item
    var digitArray      = timeFormat.match(/\d+/g);
    var totalSeconds    = 0;

    // only 1 value in array
    if (timeFormat.indexOf('H') > -1 && timeFormat.indexOf('M') == -1 && timeFormat.indexOf('S') == -1) {
        totalSeconds    += getIntValue(digitArray[0]) * 60 * 60;
    }

    else if (timeFormat.indexOf('H') == -1 && timeFormat.indexOf('M') > -1 && timeFormat.indexOf('S') == -1) {
        totalSeconds    += getIntValue(digitArray[0]) * 60;
    }

    else if (timeFormat.indexOf('H') == -1 && timeFormat.indexOf('M') == -1 && timeFormat.indexOf('S') > -1) {
        totalSeconds    += getIntValue(digitArray[0]);
    }


    // 2 values in array
    else if (timeFormat.indexOf('H') > -1 && timeFormat.indexOf('M') > -1 && timeFormat.indexOf('S') == -1) {
        totalSeconds    += getIntValue(digitArray[0]) * 60 * 60;
        totalSeconds    += getIntValue(digitArray[1]) * 60;
    }

    else if (timeFormat.indexOf('H') > -1 && timeFormat.indexOf('M') == -1 && timeFormat.indexOf('S') > -1) {
        totalSeconds    += getIntValue(digitArray[0]) * 60 * 60;
        totalSeconds    += getIntValue(digitArray[1]);
    }

    else if (timeFormat.indexOf('H') == -1 && timeFormat.indexOf('M') > -1 && timeFormat.indexOf('S') > -1) {
        totalSeconds    += getIntValue(digitArray[0]) * 60;
        totalSeconds    += getIntValue(digitArray[1]);
    }


    // all 3 values
    else if (timeFormat.indexOf('H') > -1 && timeFormat.indexOf('M') > -1 && timeFormat.indexOf('S') > -1) {
        totalSeconds    += getIntValue(digitArray[0]) * 60 * 60;
        totalSeconds    += getIntValue(digitArray[1]) * 60;
        totalSeconds    += getIntValue(digitArray[2]);
    }

//  console.log(timeFormat, totalSeconds);

    return totalSeconds;
}
function getIntValue(value) {
    if (value === null) {
        return 0;
    }

    else {

        var intValue = 0;
        try {
            intValue        = parseInt(value);
            if (isNaN(intValue)) {
                intValue    = 0;
            }
        } catch (ex) { }

        return Math.floor(intValue);
    }
}
0
bladnman

Python

Cela fonctionne en analysant la chaîne d'entrée, un caractère à la fois, si le caractère est numérique, il l'ajoute simplement (chaîne ajoute, pas une addition mathématique) à la valeur actuelle en cours d'analyse . la valeur est affectée à la variable appropriée (semaine, jour, heure, minute, seconde) et la valeur est ensuite réinitialisée et prête à prendre la valeur suivante… .. Enfin, elle additionne le nombre de secondes des 5 valeurs analysées.

def ytDurationToSeconds(duration): #eg P1W2DT6H21M32S
    week = 0
    day  = 0
    hour = 0
    min  = 0
    sec  = 0

    duration = duration.lower()

    value = ''
    for c in duration:
        if c.isdigit():
            value += c
            continue

        Elif c == 'p':
            pass
        Elif c == 't':
            pass
        Elif c == 'w':
            week = int(value) * 604800
        Elif c == 'd':
            day = int(value)  * 86400
        Elif c == 'h':
            hour = int(value) * 3600
        Elif c == 'm':
            min = int(value)  * 60
        Elif c == 's':
            sec = int(value)

        value = ''

    return week + day + hour + min + sec
0
Sean Poyser