timesince.py 2.5 KB

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