可读时间格式(带好语法!)

时间:2016-10-04 15:10:11

标签: python time control-flow

我一直在阅读关于转换输入秒数的方法的帖子上的帖子,这些方法应该作为具有给定持续时间(小时,分钟,秒)的正式字符串输出。但是我想知道如何格式化它以便它解释单一化/复数化,当我知道时,例如,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

5 个答案:

答案 0 :(得分: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)

编辑:所以我添加了一个功能来美化输出,列表中的最后一个术语将由“和”和其他所有其他术语以逗号分隔。即使您在代码中添加更多间隔(例如('days', 86400)),这仍然有效。输出现在看起来像2 hours, 1 minute and 43 seconds25 minutes and 14 seconds

答案 1 :(得分: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"

答案 2 :(得分: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/ 这是我从

中偷走几乎所有第二组代码的地方

答案 3 :(得分: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)

答案 4 :(得分: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