2013-05-24 5 views
6

Aus Gründen des Interesses möchte ich Videodauer von YouTubes ISO 8601 in Sekunden konvertieren. Um meine Lösung zukunftssicher zu machen, wählte ich a really long video aus, um es zu testen.Wie wird die YouTube API-Dauer in Sekunden umgewandelt?

Die API bietet dies für die Dauer - "duration": "P1W2DT6H21M32S"

Ich habe versucht, diese Dauer mit dateutil Parsen wie in stackoverflow.com/questions/969285 vorgeschlagen.

import dateutil.parser 
duration = = dateutil.parser.parse('P1W2DT6H21M32S') 

Dies löst eine Ausnahme

TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int' 

Was mir fehlt?

Antwort

13

Das integrierte dateutil-Modul von Python unterstützt nur das Analysieren von ISO 8601-Daten, nicht ISO 8601-Dauer. Dafür können Sie die Bibliothek "isodate" verwenden (in pypi unter https://pypi.python.org/pypi/isodate - installieren Sie sie über pip oder easy_install). Diese Bibliothek unterstützt vollständig die ISO 8601-Dauer und konvertiert sie in datetime.timedelta-Objekte. Wenn Sie also die Bibliothek importiert haben, ist es so einfach wie:

dur=isodate.parse_duration('P1W2DT6H21M32S') 
print dur.total_seconds() 
+0

wow, bedenkt, dass ich meine eigenen Parser geschrieben, das macht es nur alles so einfach scheint :) Dank! –

+0

@MorganWilde Eines der großen Dinge über Python ist, dass Sie normalerweise eine vorhandene Lösung finden können, wenn nicht in der Standardbibliothek, dann auf pypi. Es empfiehlt sich, alles zu vermeiden, wenn eine Lösung bereits existiert (in jeder Sprache, nicht nur in Python). – zstewart

1

Ist das Video nicht 1 Woche, 2 Tage, 6 Stunden 21 Minuten 32 Sekunden lang?

Youtube zeigt es als 222 Stunden 21 Minuten 17 Sekunden; 1 * 7 * 24 + 2 * 24 + 6 = 222. Ich weiß nicht, woher 17 Sekunden vs 32 Sekunden Diskrepanz kommt; kann auch ein Rundungsfehler sein.

Für mich ist es nicht so schwer einen Parser zu schreiben. Leider scheint dateutil Intervalle nicht zu analysieren, nur Datum-Zeit-Punkte.

Update:

Ich sehe, dass ein Paket für diese gibt es, aber nur als ein Beispiel für regexp Macht, Kürze und unverständlich Syntax, hier ist ein Parser für Sie:

import re 

# see http://en.wikipedia.org/wiki/ISO_8601#Durations 
ISO_8601_period_rx = re.compile(
    'P' # designates a period 
    '(?:(?P<years>\d+)Y)?' # years 
    '(?:(?P<months>\d+)M)?' # months 
    '(?:(?P<weeks>\d+)W)?' # weeks 
    '(?:(?P<days>\d+)D)?' # days 
    '(?:T' # time part must begin with a T 
    '(?:(?P<hours>\d+)H)?' # hourss 
    '(?:(?P<minutes>\d+)M)?' # minutes 
    '(?:(?P<seconds>\d+)S)?' # seconds 
    ')?' # end of time part 
) 


from pprint import pprint 
pprint(ISO_8601_period_rx.match('P1W2DT6H21M32S').groupdict()) 

# {'days': '2', 
# 'hours': '6', 
# 'minutes': '21', 
# 'months': None, 
# 'seconds': '32', 
# 'weeks': '1', 
# 'years': None} 

I Aus diesen Daten errechne ich hier bewusst nicht die genaue Anzahl der Sekunden. Es sieht trivial aus (siehe oben), ist es aber nicht. Zum Beispiel ist die Entfernung von 2 Monaten vom 1. Januar 58 Tage (30 + 28) oder 59 (30 + 29), abhängig vom Jahr, während ab dem 1. März immer 61 Tage sind. Eine korrekte Kalenderumsetzung sollte all dies berücksichtigen. Für eine Youtube-Cliplängenberechnung muss es übermäßig sein.

+0

es scheint, dass die beste Lösung ist so weit :) –

+0

Check out, wie schrecklich meine Lösung ... ist: D Brevity sicherlich entkommt meinen Verstand ... –

+0

@MorganWilde: gut Besuche Mine in der aktualisierte Antwort. Ich schreibe nicht immer endliche Automaten, aber wenn ich das tue, versuche ich eine bekannte domänenspezifische Sprache zu verwenden :) – 9000

0

Also das ist, was ich kam mit - einem benutzerdefinierten Parser die Zeit zu interpretieren:

def durationToSeconds(duration): 
    """ 
    duration - ISO 8601 time format 
    examples : 
     'P1W2DT6H21M32S' - 1 week, 2 days, 6 hours, 21 mins, 32 secs, 
     'PT7M15S' - 7 mins, 15 secs 
    """ 
    split = duration.split('T') 
    period = split[0] 
    time = split[1] 
    timeD = {} 

    # days & weeks 
    if len(period) > 1: 
     timeD['days'] = int(period[-2:-1]) 
    if len(period) > 3: 
     timeD['weeks'] = int(period[:-3].replace('P', '')) 

    # hours, minutes & seconds 
    if len(time.split('H')) > 1: 
     timeD['hours'] = int(time.split('H')[0]) 
     time = time.split('H')[1] 
    if len(time.split('M')) > 1: 
     timeD['minutes'] = int(time.split('M')[0]) 
     time = time.split('M')[1]  
    if len(time.split('S')) > 1: 
     timeD['seconds'] = int(time.split('S')[0]) 

    # convert to seconds 
    timeS = timeD.get('weeks', 0) * (7*24*60*60) + \ 
      timeD.get('days', 0) * (24*60*60) + \ 
      timeD.get('hours', 0) * (60*60) + \ 
      timeD.get('minutes', 0) * (60) + \ 
      timeD.get('seconds', 0) 

    return timeS 

Jetzt ist es wahrscheinlich ist super nicht kühl und so weiter, aber es funktioniert, so dass ich zu teilen, weil Ich sorge mich um Sie Leute.

4

Funktioniert auf Python 2.7 +. Angenommen von einem JavaScript one-liner for Youtube v3 question here.

import re 

def YTDurationToSeconds(duration): 
    match = re.match('PT(\d+H)?(\d+M)?(\d+S)?', duration).groups() 
    hours = _js_parseInt(match[0]) if match[0] else 0 
    minutes = _js_parseInt(match[1]) if match[1] else 0 
    seconds = _js_parseInt(match[2]) if match[2] else 0 
    return hours * 3600 + minutes * 60 + seconds 

# js-like parseInt 
# https://gist.github.com/douglasmiranda/2174255 
def _js_parseInt(string): 
    return int(''.join([x for x in string if x.isdigit()])) 

# example output 
YTDurationToSeconds(u'PT15M33S') 
# 933 

Griffe iso8061 Dauer Format Umfang Youtube Dies funktioniert Verbraucht bis zu Stunden

1

durch die Eingabezeichenfolge 1 Zeichen in einer Zeit, Parsen, wenn der Charakter es es numerisch ist einfach addiert (string hinzufügen, nicht mathematische Hinzufügen) zum aktuellen Wert, der analysiert wird. Wenn es sich um ein ‚wdhms‘ ist der aktuelle Wert der entsprechenden Variablen zugewiesen (Woche, Tag, Stunde, Minute, Sekunde), und der Wert wird dann zurückgesetzt bereit, den nächsten Wert zu nehmen. Schließlich summieren Sie die Anzahl der Sekunden aus den 5 analysierten Werten.

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 
Verwandte Themen