You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

73 lines
2.6 KiB

  1. from __future__ import unicode_literals
  2. import calendar
  3. import datetime
  4. from django.utils.html import avoid_wrapping
  5. from django.utils.timezone import is_aware, utc
  6. from django.utils.translation import ugettext, ungettext_lazy
  7. TIMESINCE_CHUNKS = (
  8. (60 * 60 * 24 * 365, ungettext_lazy('%d year', '%d years')),
  9. (60 * 60 * 24 * 30, ungettext_lazy('%d month', '%d months')),
  10. (60 * 60 * 24 * 7, ungettext_lazy('%d week', '%d weeks')),
  11. (60 * 60 * 24, ungettext_lazy('%d day', '%d days')),
  12. (60 * 60, ungettext_lazy('%d hour', '%d hours')),
  13. (60, ungettext_lazy('%d minute', '%d minutes'))
  14. )
  15. def timesince(d, now=None, reversed=False):
  16. """
  17. Takes two datetime objects and returns the time between d and now
  18. as a nicely formatted string, e.g. "10 minutes". If d occurs after now,
  19. then "0 minutes" is returned.
  20. Units used are years, months, weeks, days, hours, and minutes.
  21. Seconds and microseconds are ignored. Up to two adjacent units will be
  22. displayed. For example, "2 weeks, 3 days" and "1 year, 3 months" are
  23. possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not.
  24. Adapted from
  25. http://web.archive.org/web/20060617175230/http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
  26. """
  27. # Convert datetime.date to datetime.datetime for comparison.
  28. if not isinstance(d, datetime.datetime):
  29. d = datetime.datetime(d.year, d.month, d.day)
  30. if now and not isinstance(now, datetime.datetime):
  31. now = datetime.datetime(now.year, now.month, now.day)
  32. if not now:
  33. now = datetime.datetime.now(utc if is_aware(d) else None)
  34. delta = (d - now) if reversed else (now - d)
  35. # Deal with leapyears by subtracing the number of leapdays
  36. delta -= datetime.timedelta(calendar.leapdays(d.year, now.year))
  37. # ignore microseconds
  38. since = delta.days * 24 * 60 * 60 + delta.seconds
  39. if since <= 0:
  40. # d is in the future compared to now, stop processing.
  41. return avoid_wrapping(ugettext('0 minutes'))
  42. for i, (seconds, name) in enumerate(TIMESINCE_CHUNKS):
  43. count = since // seconds
  44. if count != 0:
  45. break
  46. result = avoid_wrapping(name % count)
  47. if i + 1 < len(TIMESINCE_CHUNKS):
  48. # Now get the second item
  49. seconds2, name2 = TIMESINCE_CHUNKS[i + 1]
  50. count2 = (since - (seconds * count)) // seconds2
  51. if count2 != 0:
  52. result += ugettext(', ') + avoid_wrapping(name2 % count2)
  53. return result
  54. def timeuntil(d, now=None):
  55. """
  56. Like timesince, but returns a string measuring the time until
  57. the given time.
  58. """
  59. return timesince(d, now, reversed=True)