2016-10-04 5 views
1

Я читал сообщения о сообщениях методов преобразования входного количества секунд, которые должны выводиться как формальная строка с заданными длительностью (часами, минутами, секундами) , Но я хочу знать, как отформатировать его так, чтобы он учитывал особенности/плюрализацию, когда я знаю, например, 62 секунд следует читать как "1 minute and 2 seconds", а не 120 секунд, что просто "2 minutes".Формат считываемого времени (с хорошей грамматикой!)

Другим критерием является то, что он должен вернуть "now", если секунды 0.

Вот мой код до сих пор:

def format_duration(seconds, granularity = 2): 
    intervals = (('hours', 3600), ('minutes', 60), ('seconds', 1)) 
    human_time = [] 
    for name, count in intervals: 
     value = seconds // count 
     if value: 
      seconds -= value * count 
      if value == 1: 
       name = name.rstrip('s') 
      human_time.append("{} {}".format(value, name)) 
     else: 
      return "now" 
    return ','.join(human_time[:granularity]) 

Пожалуйста, помогите! Благодаря!

MJ

ответ

2

Ваш код уже работает достаточно хорошо, вы только одна проблема с вашим return "now", что я зафиксированный в коде ниже. Что еще вы хотите, чтобы ваш код делал?

def prettyList(human_time): 
    if len(human_time) > 1: 
     return ' '.join([', '.join(human_time[:-1]), "and", human_time[-1]]) 
    elif len(human_time) == 1: 
     return human_time[0] 
    else: 
     return "" 

def format_duration(seconds, granularity = 2): 
    intervals = (('hours', 3600), ('minutes', 60), ('seconds', 1)) 
    human_time = [] 
    for name, count in intervals: 
     value = seconds // count 
     if value: 
      seconds -= value * count 
      if value == 1: 
       name = name.rstrip('s') 
      human_time.append("{} {}".format(value, name)) 
    if not human_time: 
     return "now" 
    human_time = human_time[:granularity] 
    return prettyList(human_time) 

Edit: я добавил функцию приукрасить вывод, последние члены в списке будут separed символом «и» и все другие до запятой. Это будет работать, даже если вы добавите в свой код дополнительные интервалы (например, ('days', 86400)). Выход теперь выглядит как 2 hours, 1 minute and 43 seconds или 25 minutes and 14 seconds.

+0

это на самом деле очень полезно - в настоящее время мой код отсутствует правильный «и» конъюнкция, скажем, для примера, как «1 минуты и 2 секунды ». Я думал, что это исправлено с помощью настройки 10, да? Есть идеи? «И» должно быть там в зависимости ... –

+0

Думаю, вы хотите «и» для последнего соединения и запятые для всего, прежде чем, чтобы он выходил «2 часа, 1 минута и 58 секунд»? – Efferalgan

+0

точно! и это, конечно, применимо и к более коротким срокам, когда я не составлял часов, минут и секунд. Есть идеи? –

2

Сделаны некоторые твики для читаемости:

def pretty_list(human_time): 
    return human_time[0] if len(human_time) == 1 else ' '.join([', '.join(human_time[:-1]), "and", human_time[-1]]) 


def get_intervals(seconds): 
    m, s = divmod(seconds, 60) 
    h, m = divmod(m, 60) 
    return (
     ("hour", h), 
     ("minute", m), 
     ("second", s) 
    ) 


def format_duration(seconds, granularity=3): 

    intervals = get_intervals(seconds) 
    human_time = [] 
    for name, value in intervals: 
     if value == 0: 
      continue 
     elif value == 1: 
      human_time.append("{} {}".format(value, name)) 
     else: 
      human_time.append("{} {}s".format(value, name)) 
    return (pretty_list(human_time[:granularity])) if len(human_time) != 0 else "now" 
+0

Вы можете добавить часть pretty_list из @Efferalgan, чтобы получить лучшее из обоих миров! –

+0

Мне очень нравится эта возможность из-за ее удобочитаемости, намного проще переваривать линию для линии, но она по-прежнему не учитывает «и», что необходимо в примере типа «1 минута и 2 секунды». –

+0

Готово! :) Разделенная функция тоже –

0

Я нашел его! Я на самом деле нужен больше интервалов - длительности попросили были большее время, чем я думал ...

def prettyList(human_time): 
    if len(human_time) > 1: 
     return ' '.join([', '.join(human_time[:-1]), "and", human_time[-1]]) 
    elif len(human_time) == 1: 
     return human_time[0] 
    else: 
     return "" 

def format_duration(seconds, granularity = 4): 
    intervals = (('years', 29030400), ('months', 2419200), ('weeks', 604800),('days', 86400),('hours', 3600), ('minutes', 60), ('seconds', 1)) 
    human_time = [] 
    for name, count in intervals: 
     value = seconds // count 
     if value: 
      seconds -= value * count 
      if value == 1: 
       name = name.rstrip('s') 
      human_time.append("{} {}".format(value, name)) 
    if not human_time: 
     return "now" 
    human_time = human_time[:granularity] 
    return prettyList(human_time) 
+0

woops! теперь он говорит: «6 месяцев, 2 недели, 1 час и 44 минуты» должны равняться «182 дням, 1 час, 44 минуты и 40 секунд» ... любые идеи? –

+0

Что вы имеете в виду? Вы вводите количество секунд, соответствующее 6 месяцам, и выводит «182 дня и т. Д.»? – Efferalgan

+0

по какой-то причине он просит несколько дней, часов, минут и секунд. –

1

Вы можете попробовать код для каждого варианта:

def timestamp(ctime): 
    sec = int(ctime) 
    if sec == 0: 
     return "Now" 
    m, s = divmod(sec, 60) 
    h, m = divmod(m, 60) 
    if h == 1: hr_t = 'Hour' 
    else: hr_t = 'Hours' 
    if m == 1: mn_t = 'Minute' 
    else: mn_t = 'Minutes' 
    if s == 1: sc_t = 'Second' 
    else: sc_t = 'Seconds' 
    time_stamp = "" 
    if h > 0 and m ==0 and s ==0: 
     time_stamp = "%02d %s " % (h, hr_t) 
    elif h > 0: 
     time_stamp = "%02d %s, " % (h, hr_t) 
    if m > 0 and s !=0: 
     time_stamp = time_stamp +"%02d %s and %02d %s" % (m, mn_t, s, sc_t) 
    elif m > 0 and s == 0: 
     time_stamp = time_stamp +"%02d %s" % (m, mn_t) 
    elif m == 0 and s != 0: 
     time_stamp = time_stamp +"%02d %s" % (s, sc_t) 
    return time_stamp 
print (timestamp(11024)) 
print (timestamp(0)) 
print (timestamp(31)) 
print (timestamp(102)) 
print (timestamp(61)) 
print (timestamp(60)) 
print (timestamp(3600)) 
print (timestamp(3632)) 
03 Hours, 03 Minutes and 44 Seconds 
Now 
31 Seconds 
01 Minute and 42 Seconds 
01 Minute and 01 Second 
01 Minute 
01 Hour 
01 Hour, 32 Seconds 

Или вы можете использовать опцию relativedelta в dateutil а затем вынуть кости из него.

from dateutil.relativedelta import relativedelta 
attrs = ['years', 'months', 'days', 'hours', 'minutes', 'seconds'] 
human_readable = lambda delta: ['%d %s ' % (getattr(delta, attr), getattr(delta, attr) != 1 and attr or attr[:-1]) for attr in attrs if getattr(delta, attr) or attr == attrs[-1]] 
readable='' 
for i in human_readable(relativedelta(seconds=1113600)): 
    readable += i 
print readable 
print human_readable(relativedelta(seconds=13600)) 
print human_readable(relativedelta(seconds=36)) 
print human_readable(relativedelta(seconds=60)) 
print human_readable(relativedelta(seconds=3600)) 
12 days 21 hours 20 minutes 0 seconds 
['3 hours ', '46 minutes ', '40 seconds '] 
['36 seconds '] 
['1 minute ', '0 seconds '] 
['1 hour ', '0 seconds '] 

Дополнительные примеры второго примера см: http://code.activestate.com/recipes/578113-human-readable-format-for-a-given-time-delta/ где я украл почти все второй набор кода из

+0

I собирался опубликовать что-то в этом направлении. Спасибо, что пощадил мне исследование :) – Efferalgan

0

Я думаю, что покрыли все основания здесь, но я что кто-то даст мне знать, если я сделал ошибку (большой или маленький) :)

from dateutil.relativedelta import relativedelta 
def convertdate(secs): 
    raw_date = relativedelta(seconds=secs) 
    years, days = divmod(raw_date.days, 365) # To crudely cater for leap years/365.2425 
    hours = raw_date.hours 
    minutes = raw_date.minutes 
    seconds = raw_date.seconds 
    full = [years,days,hours,minutes,seconds] 
    date_text=['','','','',''] 
    if years == 1: date_text[0] = "Year" 
    else: date_text[0] = "Years" 
    if days == 1: date_text[1] = "Day" 
    else: date_text[1] = "Days" 
    if hours == 1: date_text[2] = "Hour" 
    else: date_text[2] = "Hours" 
    if minutes == 1: date_text[3] = "Minute" 
    else: date_text[3] = "Minutes" 
    if seconds == 1: date_text[4] = "Second" 
    else: date_text[4] = "Seconds" 
    first_pos = 0 
    final_pos = 0 
    element_count = 0 
    # Find the first and final set positions and the number of returned values 
    for i in range(5): 
     if full[i] != 0: 
      final_pos = i 
      element_count +=1 
      if first_pos == 0: 
       first_pos = i 
    # Return "now" and any single value 
    if element_count == 0: 
     return "Now" 
    if element_count == 1: 
     return "%02d %s" % (full[final_pos],date_text[final_pos]) 
    # Initially define the separators 
    separators=['','','','',''] 
    ret_str='' 
    for i in range(4): 
     if full[i] != 0: 
      separators[i] = ', ' 
    separators[final_pos] = '' 
    # Redefine the final separator 
    for i in range(4,-1,-1): 
     if separators[i] == ', ': 
      separators[i] = ' and ' 
      break 
    #Build the readable formatted time string 
    for i in range(5): 
     if full[i] != 0: 
      ret_str += "%02d %s%s" % (full[i],date_text[i],separators[i]) 
    return ret_str 
print convertdate(1111113601) 
print convertdate(1111113635) 
print convertdate(1111113600) 
print convertdate(1111111200) 
print convertdate(1111104000) 
print convertdate(1111104005) 
print convertdate(11113240) 
print convertdate(11059240) 
print convertdate(11113600) 
print convertdate(36) 
print convertdate(60) 
print convertdate(61) 
print convertdate(121) 
print convertdate(122) 
print convertdate(120) 
print convertdate(3600) 
print convertdate(3601) 

35 Years, 85 Days, 02 Hours, 40 Minutes and 01 Second 
35 Years, 85 Days, 02 Hours, 40 Minutes and 35 Seconds 
35 Years, 85 Days, 02 Hours and 40 Minutes 
35 Years, 85 Days and 02 Hours 
35 Years and 85 Days 
35 Years, 85 Days and 05 Seconds 
128 Days, 15 Hours and 40 Seconds 
128 Days and 40 Seconds 
128 Days, 15 Hours, 06 Minutes and 40 Seconds 
36 Seconds 
01 Minute 
01 Minute and 01 Second 
02 Minutes and 01 Second 
02 Minutes and 02 Seconds 
02 Minutes 
01 Hour 
01 Hour and 01 Second