diff --git a/rhodecode/lib/utils2.py b/rhodecode/lib/utils2.py --- a/rhodecode/lib/utils2.py +++ b/rhodecode/lib/utils2.py @@ -24,6 +24,8 @@ # along with this program. If not, see . import re +from datetime import datetime +from pylons.i18n.translation import _, ungettext from rhodecode.lib.vcs.utils.lazy import LazyProperty @@ -284,40 +286,76 @@ def engine_from_config(configuration, pr return engine -def age(curdate): +def age(prevdate): """ turns a datetime into an age string. - :param curdate: datetime object + :param prevdate: datetime object :rtype: unicode :returns: unicode words describing age """ - from datetime import datetime - from webhelpers.date import time_ago_in_words + order = ['year', 'month', 'day', 'hour', 'minute', 'second'] + deltas = {} + + # Get date parts deltas + now = datetime.now() + for part in order: + deltas[part] = getattr(now, part) - getattr(prevdate, part) - _ = lambda s: s + # Fix negative offsets (there is 1 second between 10:59:59 and 11:00:00, + # not 1 hour, -59 minutes and -59 seconds) - if not curdate: - return '' + for num, length in [(5, 60), (4, 60), (3, 24)]: # seconds, minutes, hours + part = order[num] + carry_part = order[num - 1] + + if deltas[part] < 0: + deltas[part] += length + deltas[carry_part] -= 1 - agescales = [(_(u"year"), 3600 * 24 * 365), - (_(u"month"), 3600 * 24 * 30), - (_(u"day"), 3600 * 24), - (_(u"hour"), 3600), - (_(u"minute"), 60), - (_(u"second"), 1), ] - - age = datetime.now() - curdate - age_seconds = (age.days * agescales[2][1]) + age.seconds - pos = 1 - for scale in agescales: - if scale[1] <= age_seconds: - if pos == 6: - pos = 5 - return '%s %s' % (time_ago_in_words(curdate, - agescales[pos][0]), _('ago')) - pos += 1 + # Same thing for days except that the increment depends on the (variable) + # number of days in the month + month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + if deltas['day'] < 0: + if prevdate.month == 2 and (prevdate.year % 4 == 0 and + (prevdate.year % 100 != 0 or prevdate.year % 400 == 0)): + deltas['day'] += 29 + else: + deltas['day'] += month_lengths[prevdate.month - 1] + + deltas['month'] -= 1 + + if deltas['month'] < 0: + deltas['month'] += 12 + deltas['year'] -= 1 + + # Format the result + fmt_funcs = { + 'year': lambda d: ungettext(u'%d year', '%d years', d) % d, + 'month': lambda d: ungettext(u'%d month', '%d months', d) % d, + 'day': lambda d: ungettext(u'%d day', '%d days', d) % d, + 'hour': lambda d: ungettext(u'%d hour', '%d hours', d) % d, + 'minute': lambda d: ungettext(u'%d minute', '%d minutes', d) % d, + 'second': lambda d: ungettext(u'%d second', '%d seconds', d) % d, + } + + for i, part in enumerate(order): + value = deltas[part] + if value == 0: + continue + + if i < 5: + sub_part = order[i + 1] + sub_value = deltas[sub_part] + else: + sub_value = 0 + + if sub_value == 0: + return _(u'%s ago') % fmt_funcs[part](value) + + return _(u'%s and %s ago') % (fmt_funcs[part](value), + fmt_funcs[sub_part](sub_value)) return _(u'just now')