|
1 import datetime |
|
2 import time |
|
3 |
|
4 from django.utils.tzinfo import LocalTimezone |
|
5 from django.utils.translation import ungettext, ugettext |
|
6 |
|
7 def timesince(d, now=None): |
|
8 """ |
|
9 Takes two datetime objects and returns the time between d and now |
|
10 as a nicely formatted string, e.g. "10 minutes". If d occurs after now, |
|
11 then "0 minutes" is returned. |
|
12 |
|
13 Units used are years, months, weeks, days, hours, and minutes. |
|
14 Seconds and microseconds are ignored. Up to two adjacent units will be |
|
15 displayed. For example, "2 weeks, 3 days" and "1 year, 3 months" are |
|
16 possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not. |
|
17 |
|
18 Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since |
|
19 """ |
|
20 chunks = ( |
|
21 (60 * 60 * 24 * 365, lambda n: ungettext('year', 'years', n)), |
|
22 (60 * 60 * 24 * 30, lambda n: ungettext('month', 'months', n)), |
|
23 (60 * 60 * 24 * 7, lambda n : ungettext('week', 'weeks', n)), |
|
24 (60 * 60 * 24, lambda n : ungettext('day', 'days', n)), |
|
25 (60 * 60, lambda n: ungettext('hour', 'hours', n)), |
|
26 (60, lambda n: ungettext('minute', 'minutes', n)) |
|
27 ) |
|
28 # Convert datetime.date to datetime.datetime for comparison |
|
29 if d.__class__ is not datetime.datetime: |
|
30 d = datetime.datetime(d.year, d.month, d.day) |
|
31 if now: |
|
32 t = now.timetuple() |
|
33 else: |
|
34 t = time.localtime() |
|
35 if d.tzinfo: |
|
36 tz = LocalTimezone(d) |
|
37 else: |
|
38 tz = None |
|
39 now = datetime.datetime(t[0], t[1], t[2], t[3], t[4], t[5], tzinfo=tz) |
|
40 |
|
41 # ignore microsecond part of 'd' since we removed it from 'now' |
|
42 delta = now - (d - datetime.timedelta(0, 0, d.microsecond)) |
|
43 since = delta.days * 24 * 60 * 60 + delta.seconds |
|
44 if since <= 0: |
|
45 # d is in the future compared to now, stop processing. |
|
46 return u'0 ' + ugettext('minutes') |
|
47 for i, (seconds, name) in enumerate(chunks): |
|
48 count = since // seconds |
|
49 if count != 0: |
|
50 break |
|
51 s = ugettext('%(number)d %(type)s') % {'number': count, 'type': name(count)} |
|
52 if i + 1 < len(chunks): |
|
53 # Now get the second item |
|
54 seconds2, name2 = chunks[i + 1] |
|
55 count2 = (since - (seconds * count)) // seconds2 |
|
56 if count2 != 0: |
|
57 s += ugettext(', %(number)d %(type)s') % {'number': count2, 'type': name2(count2)} |
|
58 return s |
|
59 |
|
60 def timeuntil(d, now=None): |
|
61 """ |
|
62 Like timesince, but returns a string measuring the time until |
|
63 the given time. |
|
64 """ |
|
65 if now == None: |
|
66 now = datetime.datetime.now() |
|
67 return timesince(now, d) |