Coverage for superdjango/db/timed/models.py : 0%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Imports
3from datetime import timedelta
4from django.db import models
5from django.utils.translation import gettext_lazy as _
6from django.utils.timezone import now
7from ..audit.utils import is_audit_model
9# Exports
11__all__ = (
12 "TimedModel",
13)
15# Constants
17SECONDS_PER_DAY = 24 * 60 * 60
19# Models
22class TimedModel(models.Model):
23 """Provides date/time fields for noting a starting time and ending time, as well as convenience methods for
24 calculating elapsed time.
26 .. code-block:: python
28 from superdjango.db.timed.models import TimedModel
30 class Meeting(TimedModel):
32 end_date = models.DateField()
33 end_time = models.TimeField()
34 is_all_day = models.BooleanField()
35 start_date = models.DateField()
36 start_time = models.TimeField()
38 """
40 timer_elapsed_seconds = models.PositiveIntegerField(
41 _("elapsed seconds"),
42 blank=True,
43 help_text=_("Total seconds elapsed from start to end."),
44 null=True
45 )
47 timer_is_running = models.BooleanField(
48 _("running"),
49 default=False,
50 help_text=_("Indicates whether the timer is running.")
51 )
53 timer_start_dt = models.DateTimeField(
54 _("start date/time"),
55 blank=True,
56 help_text=_("Date and time the timer was started."),
57 null=True,
58 )
60 timer_stop_dt = models.DateTimeField(
61 _("stop date/time"),
62 blank=True,
63 help_text=_("Date and time the timer was stopped."),
64 null=True
65 )
67 class Meta:
68 abstract = True
70 @property
71 def elapsed_duration(self):
72 """Get the elapsed duration either as the current ``timer_elapsed_seconds`` or by calling
73 ``get_elapsed_duration()``.
75 :rtype: timedelta
77 """
78 if self.timer_elapsed_seconds:
79 return timedelta(seconds=self.timer_elapsed_seconds)
81 return self.get_elapsed_duration()
83 def get_elapsed_duration(self):
84 """Get the time that has elapsed as a duration.
86 :rtype: timedelta
88 """
89 return timedelta(seconds=self.get_timer_elapsed_seconds())
91 def get_elapsed_duration_display(self):
92 """Get a human-friendly display for the duration.
94 :rtype: str
96 """
97 d = self.get_elapsed_duration()
98 total_seconds = d.seconds
100 if total_seconds == 0:
101 return ""
103 hours, remainder = divmod(total_seconds, 3600)
104 minutes, seconds = divmod(remainder, 60)
106 s = list()
108 if hours > 0:
109 s.append(str(hours))
110 if hours == 1:
111 s.append(str(_("hour")))
112 else:
113 s.append(str(_("hours")))
115 if minutes > 0:
116 s.append(str(minutes))
117 if minutes == 1:
118 s.append(str(_("minute")))
119 else:
120 s.append(str(_("minutes")))
122 return " ".join(s)
124 def get_timer_elapsed_seconds(self):
125 """Get the number of seconds that have passed since the timer started until now *or* until the item ended, if a
126 stop datetime is available.
128 :rtype: int
130 This method will:
132 - Calculate the elapsed seconds from the start datetime until the current datetime.
133 - Also include the elapsed seconds already calculated.
135 """
136 if not self.timer_start_dt:
137 return 0
139 current_dt = now()
141 delta = current_dt - self.timer_start_dt
143 return delta.seconds + (delta.days * SECONDS_PER_DAY) + (self.timer_elapsed_seconds or 0)
145 def reset_timer(self, user, commit=True):
146 """Reset the current timer.
148 :param user: The user updating the record. If the record is an audit model, the ``audit()`` method will be
149 called. Pass ``None`` to suppress this behavior.
150 :type user: AUTH_USER_MODEL | None
152 :param commit: Indicates whether the record should be saved after resetting the timer.
153 :type commit: bool
155 :rtype: int
156 :returns: The value of elapsed seconds prior to the reset.
158 This method will:
160 - Remove the stop datetime and set elapsed seconds to ``0``.
161 - Change the start datetime to the current datetime.
162 - Ensure that the timer is still running.
164 """
165 current_elapsed_seconds = self.timer_elapsed_seconds or 0
167 self.timer_elapsed_seconds = 0
168 self.timer_is_running = True
169 self.timer_stop_dt = None
170 self.timer_start_dt = now()
172 if is_audit_model(self) and user is not None:
173 # noinspection PyUnresolvedReferences
174 self.audit(user, commit=commit)
175 return current_elapsed_seconds
177 if commit:
178 self.save(update_fields=["timer_elapsed_seconds", "timer_is_running", "timer_stop_dt", "timer_start_dt"])
180 return current_elapsed_seconds
182 def start_timer(self, user, commit=True):
183 """Start the timer.
185 :param user: The user updating the record. If the record is an audit model, the ``audit()`` method will be
186 called. Pass ``None`` to suppress this behavior.
187 :type user: AUTH_USER_MODEL | None
189 :param commit: Indicates whether the record should be saved after
190 starting the timer.
191 :type commit: bool
193 :rtype: int
194 :returns: The current elapsed seconds if the timer is already running. Otherwise, ``0``.
196 This method will:
198 - Set the start datetime to the current datetime.
199 - Ensure that the time is running.
200 - Leave the elapsed seconds unchanged.
202 """
203 if self.timer_is_running:
204 return self.get_timer_elapsed_seconds()
206 self.timer_is_running = True
207 self.timer_start_dt = now()
209 if is_audit_model(self) and user is not None:
210 # noinspection PyUnresolvedReferences
211 self.audit(user, commit=commit)
212 return 0
214 if commit:
215 self.save(update_fields=["timer_is_running", "timer_start_dt"])
217 return 0
219 def stop_timer(self, user, commit=True):
220 """Stop the timer.
222 :param user: The user updating the record. If the record is an audit model, the ``audit()`` method will be
223 called. Pass ``None`` to suppress this behavior.
224 :type user: AUTH_USER_MODEL | None
227 :param commit: Indicates whether the record should be saved after
228 stopping the timer.
229 :type commit: bool
231 :rtype: int
232 :returns: The elpased seconds.
234 This method will:
236 - Set the stop datetime to the current datetime.
237 - Update the elapsed seconds.
238 - Ensure that the time is not running.
240 """
241 if not self.timer_is_running:
242 return self.get_timer_elapsed_seconds()
244 self.timer_elapsed_seconds = self.get_timer_elapsed_seconds()
245 self.timer_is_running = False
246 self.timer_stop_dt = now()
248 if is_audit_model(self) and user is not None:
249 # noinspection PyUnresolvedReferences
250 self.audit(user, commit=commit)
251 return self.timer_elapsed_seconds
253 if commit:
254 self.save(update_fields=["timer_elapsed_seconds", "timer_is_running", "timer_stop_dt"])
256 return self.timer_elapsed_seconds