Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/utils/timesince.py: 12%
49 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1import calendar
2import datetime
4from django.utils.html import avoid_wrapping
5from django.utils.timezone import is_aware, utc
6from django.utils.translation import gettext, ngettext_lazy
8TIME_STRINGS = {
9 "year": ngettext_lazy("%(num)d year", "%(num)d years", "num"),
10 "month": ngettext_lazy("%(num)d month", "%(num)d months", "num"),
11 "week": ngettext_lazy("%(num)d week", "%(num)d weeks", "num"),
12 "day": ngettext_lazy("%(num)d day", "%(num)d days", "num"),
13 "hour": ngettext_lazy("%(num)d hour", "%(num)d hours", "num"),
14 "minute": ngettext_lazy("%(num)d minute", "%(num)d minutes", "num"),
15}
17TIMESINCE_CHUNKS = (
18 (60 * 60 * 24 * 365, "year"),
19 (60 * 60 * 24 * 30, "month"),
20 (60 * 60 * 24 * 7, "week"),
21 (60 * 60 * 24, "day"),
22 (60 * 60, "hour"),
23 (60, "minute"),
24)
27def timesince(d, now=None, reversed=False, time_strings=None, depth=2):
28 """
29 Take two datetime objects and return the time between d and now as a nicely
30 formatted string, e.g. "10 minutes". If d occurs after now, return
31 "0 minutes".
33 Units used are years, months, weeks, days, hours, and minutes.
34 Seconds and microseconds are ignored. Up to `depth` adjacent units will be
35 displayed. For example, "2 weeks, 3 days" and "1 year, 3 months" are
36 possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not.
38 `time_strings` is an optional dict of strings to replace the default
39 TIME_STRINGS dict.
41 `depth` is an optional integer to control the number of adjacent time
42 units returned.
44 Adapted from
45 https://web.archive.org/web/20060617175230/http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
46 """
47 if time_strings is None:
48 time_strings = TIME_STRINGS
49 if depth <= 0:
50 raise ValueError("depth must be greater than 0.")
51 # Convert datetime.date to datetime.datetime for comparison.
52 if not isinstance(d, datetime.datetime):
53 d = datetime.datetime(d.year, d.month, d.day)
54 if now and not isinstance(now, datetime.datetime):
55 now = datetime.datetime(now.year, now.month, now.day)
57 now = now or datetime.datetime.now(utc if is_aware(d) else None)
59 if reversed:
60 d, now = now, d
61 delta = now - d
63 # Deal with leapyears by subtracing the number of leapdays
64 leapdays = calendar.leapdays(d.year, now.year)
65 if leapdays != 0:
66 if calendar.isleap(d.year):
67 leapdays -= 1
68 elif calendar.isleap(now.year):
69 leapdays += 1
70 delta -= datetime.timedelta(leapdays)
72 # ignore microseconds
73 since = delta.days * 24 * 60 * 60 + delta.seconds
74 if since <= 0:
75 # d is in the future compared to now, stop processing.
76 return avoid_wrapping(time_strings["minute"] % {"num": 0})
77 for i, (seconds, name) in enumerate(TIMESINCE_CHUNKS):
78 count = since // seconds
79 if count != 0:
80 break
81 else:
82 return avoid_wrapping(time_strings["minute"] % {"num": 0})
83 result = []
84 current_depth = 0
85 while i < len(TIMESINCE_CHUNKS) and current_depth < depth:
86 seconds, name = TIMESINCE_CHUNKS[i]
87 count = since // seconds
88 if count == 0:
89 break
90 result.append(avoid_wrapping(time_strings[name] % {"num": count}))
91 since -= seconds * count
92 current_depth += 1
93 i += 1
94 return gettext(", ").join(result)
97def timeuntil(d, now=None, time_strings=None, depth=2):
98 """
99 Like timesince, but return a string measuring the time until the given time.
100 """
101 return timesince(d, now, reversed=True, time_strings=time_strings, depth=depth)