publik: add duration filter (#72667)
This commit is contained in:
parent
1c7d91bb19
commit
9bc4981677
|
@ -14,6 +14,7 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import datetime
|
||||||
import math
|
import math
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from decimal import DivisionByZero as DecimalDivisionByZero
|
from decimal import DivisionByZero as DecimalDivisionByZero
|
||||||
|
@ -23,6 +24,8 @@ from django import template
|
||||||
from django.template import defaultfilters
|
from django.template import defaultfilters
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
|
from publik_django_templatetags.publik import utils
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,3 +165,16 @@ def sum_(list_):
|
||||||
return sum(parse_decimal(term) for term in list_)
|
return sum(parse_decimal(term) for term in list_)
|
||||||
except TypeError: # list_ is not iterable
|
except TypeError: # list_ is not iterable
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter(is_safe=False)
|
||||||
|
def duration(value, arg='short'):
|
||||||
|
if arg not in ('short', 'long'):
|
||||||
|
return ''
|
||||||
|
# value is expected to be a timedelta or a number of seconds
|
||||||
|
if not isinstance(value, datetime.timedelta):
|
||||||
|
try:
|
||||||
|
value = datetime.timedelta(seconds=int(value) * 60)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return ''
|
||||||
|
return utils.seconds2humanduration(int(value.total_seconds()), short=bool(arg != 'long'))
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
# publik-django-templatetags
|
||||||
|
# Copyright (C) 2023 Entr'ouvert
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Affero General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils.translation import ngettext_lazy
|
||||||
|
|
||||||
|
_minute = 60
|
||||||
|
_hour = 60 * 60
|
||||||
|
_day = _hour * 24
|
||||||
|
|
||||||
|
|
||||||
|
def list2human(stringlist):
|
||||||
|
'''Transform a string list to human enumeration'''
|
||||||
|
beginning = stringlist[:-1]
|
||||||
|
if not beginning:
|
||||||
|
return "".join(stringlist)
|
||||||
|
return _("%(first)s and %(second)s") % {'first': _(", ").join(beginning), 'second': stringlist[-1]}
|
||||||
|
|
||||||
|
|
||||||
|
def seconds2humanduration(seconds, short=False):
|
||||||
|
"""Convert a time range in seconds to a human string representation"""
|
||||||
|
if not isinstance(seconds, int):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
days = int(seconds / _day)
|
||||||
|
seconds = seconds - _day * days
|
||||||
|
hours = int(seconds / _hour)
|
||||||
|
seconds = seconds - _hour * hours
|
||||||
|
minutes = int(seconds / _minute)
|
||||||
|
seconds = seconds - _minute * minutes
|
||||||
|
human = []
|
||||||
|
if days:
|
||||||
|
human.append(ngettext_lazy('%(total)s day', '%(total)s days', days) % {'total': days})
|
||||||
|
if short:
|
||||||
|
if hours and minutes:
|
||||||
|
human.append(_('%(hours)sh%(minutes)02d') % {'hours': hours, 'minutes': minutes})
|
||||||
|
elif hours:
|
||||||
|
human.append(_('%(hours)sh') % {'hours': hours})
|
||||||
|
elif minutes:
|
||||||
|
human.append(_('%(minutes)smin') % {'minutes': minutes})
|
||||||
|
return list2human(human)
|
||||||
|
else:
|
||||||
|
if hours:
|
||||||
|
human.append(ngettext_lazy('%(total)s hour', '%(total)s hours', hours) % {'total': hours})
|
||||||
|
if minutes:
|
||||||
|
human.append(ngettext_lazy('%(total)s minute', '%(total)s minutes', minutes) % {'total': minutes})
|
||||||
|
if seconds:
|
||||||
|
human.append(ngettext_lazy('%(total)s second', '%(total)s seconds', seconds) % {'total': seconds})
|
||||||
|
return list2human(human)
|
|
@ -304,3 +304,28 @@ def test_sum():
|
||||||
assert t.render(Context({'list': None})) == '' # list is not iterable
|
assert t.render(Context({'list': None})) == '' # list is not iterable
|
||||||
assert t.render(Context({'list': '123'})) == '' # consider string as not iterable
|
assert t.render(Context({'list': '123'})) == '' # consider string as not iterable
|
||||||
assert t.render(Context()) == ''
|
assert t.render(Context()) == ''
|
||||||
|
|
||||||
|
|
||||||
|
def test_duration():
|
||||||
|
context = Context({'value': 80})
|
||||||
|
assert Template('{{ value|duration }}').render(context) == '1h20'
|
||||||
|
assert Template('{{ value|duration:"long" }}').render(context) == '1 hour and 20 minutes'
|
||||||
|
|
||||||
|
context = Context({'value': 40})
|
||||||
|
assert Template('{{ value|duration }}').render(context) == '40min'
|
||||||
|
assert Template('{{ value|duration:"long" }}').render(context) == '40 minutes'
|
||||||
|
|
||||||
|
context = Context({'value': 120})
|
||||||
|
assert Template('{{ value|duration }}').render(context) == '2h'
|
||||||
|
assert Template('{{ value|duration:"long" }}').render(context) == '2 hours'
|
||||||
|
|
||||||
|
context = Context({'value': 1510})
|
||||||
|
assert Template('{{ value|duration }}').render(context) == '1 day and 1h10'
|
||||||
|
assert Template('{{ value|duration:"long" }}').render(context) == '1 day, 1 hour and 10 minutes'
|
||||||
|
|
||||||
|
context = Context({'value': 61})
|
||||||
|
assert Template('{{ value|duration }}').render(context) == '1h01'
|
||||||
|
|
||||||
|
context = Context({'value': 'xx'})
|
||||||
|
assert Template('{{ value|duration }}').render(context) == ''
|
||||||
|
assert Template('{{ value|duration:"long" }}').render(context) == ''
|
||||||
|
|
Loading…
Reference in New Issue