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

1import calendar 

2import datetime 

3 

4from django.utils.html import avoid_wrapping 

5from django.utils.timezone import is_aware, utc 

6from django.utils.translation import gettext, ngettext_lazy 

7 

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} 

16 

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) 

25 

26 

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". 

32 

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. 

37 

38 `time_strings` is an optional dict of strings to replace the default 

39 TIME_STRINGS dict. 

40 

41 `depth` is an optional integer to control the number of adjacent time 

42 units returned. 

43 

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) 

56 

57 now = now or datetime.datetime.now(utc if is_aware(d) else None) 

58 

59 if reversed: 

60 d, now = now, d 

61 delta = now - d 

62 

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) 

71 

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) 

95 

96 

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)