1 | """Date/Time Helpers""" |
---|
2 | # Last synced with Rails copy at Revision 4674 on Aug 19th, 2006. |
---|
3 | # Note that the select_ tags are purposely not ported as they're very totally useless |
---|
4 | # and inefficient beyond comprehension. |
---|
5 | |
---|
6 | from datetime import datetime |
---|
7 | import time |
---|
8 | |
---|
9 | DEFAULT_PREFIX = 'date' |
---|
10 | |
---|
11 | def distance_of_time_in_words(from_time, to_time=0, include_seconds=False): |
---|
12 | """ |
---|
13 | Reports the approximate distance in time between two datetime objects or integers. |
---|
14 | |
---|
15 | For example, if the distance is 47 minutes, it'll return |
---|
16 | "about 1 hour". See the source for the complete wording list. |
---|
17 | |
---|
18 | Integers are interpreted as seconds from now. So, |
---|
19 | ``distance_of_time_in_words(50)`` returns "less than a minute". |
---|
20 | |
---|
21 | Set ``include_seconds`` to True if you want more detailed approximations if distance < 1 minute |
---|
22 | """ |
---|
23 | if isinstance(from_time, int): |
---|
24 | from_time = time.time()+from_time |
---|
25 | else: |
---|
26 | from_time = time.mktime(from_time.timetuple()) |
---|
27 | if isinstance(to_time, int): |
---|
28 | to_time = time.time()+to_time |
---|
29 | else: |
---|
30 | to_time = time.mktime(to_time.timetuple()) |
---|
31 | |
---|
32 | distance_in_minutes = int(round(abs(to_time-from_time)/60)) |
---|
33 | distance_in_seconds = int(round(abs(to_time-from_time))) |
---|
34 | |
---|
35 | if distance_in_minutes <= 1: |
---|
36 | if include_seconds: |
---|
37 | for remainder in [5, 10, 20]: |
---|
38 | if distance_in_seconds < remainder: |
---|
39 | return "less than %s seconds" % remainder |
---|
40 | if distance_in_seconds < 40: |
---|
41 | return "half a minute" |
---|
42 | elif distance_in_seconds < 60: |
---|
43 | return "less than a minute" |
---|
44 | else: |
---|
45 | return "1 minute" |
---|
46 | else: |
---|
47 | if distance_in_minutes == 0: |
---|
48 | return "less than a minute" |
---|
49 | else: |
---|
50 | return "1 minute" |
---|
51 | elif distance_in_minutes <= 45: |
---|
52 | return "%s minutes" % distance_in_minutes |
---|
53 | elif distance_in_minutes <= 90: |
---|
54 | return "about 1 hour" |
---|
55 | elif distance_in_minutes <= 1440: |
---|
56 | return "about %d hours" % (round(distance_in_minutes / 60.0)) |
---|
57 | elif distance_in_minutes <= 2880: |
---|
58 | return "1 day" |
---|
59 | elif distance_in_minutes <= 43220: |
---|
60 | return "%d days" % (round(distance_in_minutes / 1440)) |
---|
61 | elif distance_in_minutes <= 86400: |
---|
62 | return "about 1 month" |
---|
63 | elif distance_in_minutes <= 525960: |
---|
64 | return "%d months" % (round(distance_in_minutes / 43200)) |
---|
65 | elif distance_in_minutes <= 1051920: |
---|
66 | return "about 1 year" |
---|
67 | else: |
---|
68 | return "over %d years" % (round(distance_in_minutes / 525600)) |
---|
69 | |
---|
70 | def time_ago_in_words(from_time, include_seconds=False): |
---|
71 | """ |
---|
72 | Like distance_of_time_in_words, but where ``to_time`` is fixed to ``datetime.now()``. |
---|
73 | """ |
---|
74 | return distance_of_time_in_words(from_time, datetime.now(), include_seconds) |
---|
75 | |
---|
76 | __all__ = ['distance_of_time_in_words', 'time_ago_in_words'] |
---|