2013-05-24 5 views
6

Vì lợi ích tôi muốn chuyển đổi thời lượng video từ YouTubes ISO 8601 thành giây. Để chứng minh giải pháp của tôi trong tương lai, tôi đã chọn a really long video để kiểm tra.Cách chuyển đổi thời lượng API YouTube thành giây?

API cung cấp này cho thời gian của nó - "duration": "P1W2DT6H21M32S"

tôi đã cố gắng phân tích thời gian này với dateutil như đề xuất trong stackoverflow.com/questions/969285.

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

này ném một ngoại lệ

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

tôi đang thiếu gì?

Trả lời

13

Mô-đun ngày tháng được xây dựng sẵn của Python chỉ hỗ trợ phân tích cú pháp ngày ISO 8601, không phải thời lượng ISO 8601. Đối với điều đó, bạn có thể sử dụng thư viện "isodate" (trong pypi tại https://pypi.python.org/pypi/isodate - cài đặt thông qua pip hoặc easy_install). Thư viện này có hỗ trợ đầy đủ cho các khoảng thời gian ISO 8601, chuyển đổi chúng thành các đối tượng datetime.timedelta. Vì vậy, khi bạn đã nhập thư viện, nó đơn giản như:

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

wow, xem xét tôi đã viết trình phân tích cú pháp của riêng tôi, điều này chỉ làm cho tất cả có vẻ dễ dàng :) cảm ơn! –

+0

@ MorganWilde Một trong những điều tuyệt vời về python là bạn thường có thể tìm thấy một giải pháp hiện có, nếu không có trong thư viện chuẩn, sau đó là pypi. Đó là thực hành tốt để cố gắng tránh thực hiện bất cứ điều gì nếu một giải pháp đã tồn tại (trong bất kỳ ngôn ngữ, không chỉ python). – zstewart

1

Không phải là video 1 tuần, 2 ngày, 6 giờ 21 phút 32 giây dài?

Youtube hiển thị dưới dạng 222 giờ 21 phút 17 giây; 1 * 7 * 24 + 2 * 24 + 6 = 222. Tôi không biết 17 giây so với 32 giây khác biệt đến từ đâu, mặc dù; cũng có thể là lỗi làm tròn.

Theo tôi, viết một trình phân tích cú pháp cho điều đó không khó. Thật không may dateutil dường như không phân tích các khoảng thời gian, chỉ các điểm datetime.

Cập nhật:

tôi thấy rằng có một gói cho điều này, nhưng cũng giống như một ví dụ về sức mạnh regexp, ngắn gọn, và cú pháp không thể hiểu được, đây là một phân tích cú pháp cho bạn:

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} 

tôi cố tình không tính số giây chính xác từ những dữ liệu này ở đây. Nó trông tầm thường (xem ở trên), nhưng thực sự là không. Ví dụ, khoảng cách 2 tháng từ ngày 1 tháng 1 là 58 ngày (30 + 28) hoặc 59 (30 + 29), tùy thuộc vào năm, trong khi từ ngày 1 tháng 3, nó luôn là 61 ngày. Việc triển khai lịch thích hợp nên đưa tất cả điều này vào tài khoản; cho một tính toán chiều dài clip Youtube, nó phải là quá mức.

+0

có vẻ như đó là giải pháp tốt nhất cho đến nay :) –

+0

Kiểm tra ra cách khủng khiếp giải pháp của tôi là ...: D Ngắn gọn chắc chắn nhất thoát wits của tôi ... –

+0

@MorganWilde: tốt, kiểm tra của tôi trong câu trả lời cập nhật. Tôi không phải lúc nào cũng viết các automata hữu hạn, nhưng khi tôi làm vậy, tôi cố gắng sử dụng một ngôn ngữ cụ thể của miền nổi tiếng :) – 9000

0

Vì vậy, đây là những gì tôi đã đưa ra - một phân tích cú pháp tùy chỉnh để giải thích thời gian:

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 

Bây giờ nó có lẽ là siêu phi mát mẻ và như vậy, nhưng nó hoạt động, vì vậy tôi chia sẻ vì Tôi quan tâm đến bạn.

4

Hoạt động trên python 2.7+. Được thông qua từ một số 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 

Xử lý định dạng thời gian iso8061 đến mức độ Youtube Sử dụng tối đa giờ

1

này hoạt động bằng cách phân tích các đầu vào chuỗi 1 ký tự tại một thời điểm, nếu nhân vật là số nó chỉ đơn giản là thêm nó (string thêm, không phải toán học thêm) vào giá trị hiện tại đang được phân tích cú pháp. Nếu nó là một trong 'wdhms', giá trị hiện tại được gán cho biến thích hợp (tuần, ngày, giờ, phút, giây) và giá trị sau đó được đặt lại sẵn sàng để lấy giá trị tiếp theo. Cuối cùng, nó tính tổng số giây từ 5 giá trị được phân tích cú pháp.

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