I\'m trying to convert ISO 8601 string to seconds in JS/Node. The best I could come up with was:
function convert_time(duration) {
var a = duration.match
I've written a CoffeeScript variation (you can easily compile it at coffeescript.org when desired)
DIFFERENCE: the returning duration comes in a human readable format (e.g. 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
I've also implemented this helper function to fill < 10 values with a leading zero:
String.prototype.zeros = ( x ) ->
len = @length
if !x or len >= x then return @
zeros = ""
zeros += "0" for [0..(x-len-1)]
zeros + @
3nj0y!!!
Here's @redgetan 's solution in ES6.
I also fixed it for years, weeks and days.
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()
}
I ran into issues with the above solution. I decided to write it as obtuse as possible. I also use my own "getIntValue" in place of parseInt for extra sanity.
Just thought other searching might appreciate the update.
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);
}
}
This is not java specific, but i would like to add JAVA snippet as that may helpful to other users
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);
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;
}
works for these cases:
PT1H
PT23M
PT45S
PT1H23M
PT1H45S
PT23M45S
PT1H23M45S
Python
It works by parsing the input string 1 character at a time, if the character is numerical it simply adds it (string add, not mathematical add) to the current value being parsed. If it is one of 'wdhms' the current value is assigned to the appropriate variable (week, day, hour, minute, second), and value is then reset ready to take the next value. Finally it sum the number of seconds from the 5 parsed values.
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