I currently have my Django custom template filter like this:
from django import template
register = template.Library()
@register.filter
def duration(value):
hours = value / 60
minutes = value % 60
hours_string = str(hours) + (" hours" if hours > 1 else " hour" ) if hours else ""
minutes_string = str(minutes) + (" minutes" if minutes > 1 else " minute") if minutes else ""
return ' '.join("{hours} {minutes}".format(hours=hours_string, minutes=minutes_string).split())
Some possible outputs:
1 hour 25 minutes
2 hours
45 minutes
3 hours 1 minute
The ' '.join(....split())
trick was something I got from this solution. I realize I only need to check for the extra string at either the beginning or the end of the string (for when it's 0 hours or 0 minutes), but it seems to do the trick and maybe it's easier to read than regular expression to some people.
I also feel that I am violating DRY since I am repeating almost the exact same if-then
block twice. I was thinking of something like...
for i, unit in enumerate([hours, minutes]):
# Do some code.
return ' '.join("{hours} {minutes}".format(hours=value[0], minutes=value[1]).split())
but I couldn't figure out how to choose between "hour(s)" or "minute(s)" without another if-then
block. Also the two short-hand if-then
per line also looks a bit ugly too...
I'll appreciate any suggestions or tips. Thanks!
import datetime
def pprint(val):
if val == 1:
return '1 minute'
x = str(datetime.timedelta(minutes=val))[:-3].split(':')
r = ''
if int(x[0]):
r += x[0]+' hours' if int(x[0]) > 1 else x[0]+' hour'
if int(x[1]):
r += ' %s minutes' % int(x[1]) if int(x[1]) > 1 else ' %s minute' % int(x[0])
return r.strip()
Sample run:
>>> pprint(65)
'1 hour 5 minutes'
>>> pprint(1)
'1 minute'
>>> pprint(60)
'1 hour'
>>> pprint(61)
'1 hour 1 minute'
You can easily expand this to include days as well, but since you specifically mentioned only hours and minutes I adjusted the method.
The main heavy lifting is done by datetime.timedelta
, the rest is just string parsing.