Timer Operations

Purpose

The Timer Operations subtopic focuses on the fundamental mechanics behind the TaskTimer class responsible for tracking elapsed time. It addresses key challenges in timing tasks accurately and robustly, such as:

This subtopic is essential to the parent topic of Precise Task Timing because it implements the core logic that enables reliable, millisecond-precision timing for arbitrary code blocks or tasks. It complements other subtopics such as Current Time Utility, which supplies the timing source, and Timer Usage Demo, which illustrates practical application scenarios.

Functionality

The core operational workflow revolves around managing internal timestamps and a running state to measure elapsed time accurately:

Key Code Snippets

The following excerpts illustrate critical aspects of this subtopic's behavior:

Starting the timer only if not already running:

def start(self) -> "TaskTimer":
    if not self._running:
        self.started_at = now_ts()
        self._running = True
    return self

Stopping the timer only if running:

def stop(self) -> "TaskTimer":
    if self._running:
        self.stopped_at = now_ts()
        self._running = False
    return self

Calculating elapsed milliseconds with running and stopped states handled:

@property
def elapsed_ms(self) -> int:
    if self.started_at is None:
        return 0
    end = now_ts() if self._running and self.stopped_at is None else self.stopped_at or self.started_at
    return int((end - self.started_at) * 1000)

The design ensures that the timer behaves predictably even when methods are called in an unexpected order, such as stopping before starting or starting multiple times.

Integration

This subtopic integrates tightly with the broader timing utility by providing the reliable internal state management that the TaskTimer API exposes. While the parent topic introduces the timer concept and usage, Timer Operations dives into the implementation details that guarantee correct behavior and robustness.

Additionally, it leverages the Current Time Utility subtopic via the now_ts() function to abstract the current time retrieval. This separation allows for easier testing and potential future extension or mocking of time sources.

The timer state and elapsed time logic here form the foundation for the Timer Usage Demo, which shows how these operations translate into practical timing of code blocks.

Diagram

flowchart TD
StartCall["start() called"]
CheckRunning{"_running?"}
NotRunning["Set started_at = now_ts()"]
SetRunning["Set _running = True"]
ReturnStart["Return self"]
StopCall["stop() called"]
CheckRunningStop{"_running?"}
SetStoppedAt["Set stopped_at = now_ts()"]
SetNotRunning["Set _running = False"]
ReturnStop["Return self"]
GetElapsed["elapsed_ms requested"]
StartedNone{"started_at is None?"}
ReturnZero["Return 0"]
RunningCheck{"_running and stopped_at is None?"}
GetNow["end = now_ts()"]
UseStoppedAt["end = stopped_at or started_at"]
CalcElapsed["Return int((end - started_at)*1000)"]
ResetCall["reset() called"]
ClearStarted["started_at = None"]
ClearStopped["stopped_at = None"]
ClearRunning["_running = False"]
%% start flow
StartCall --> CheckRunning
CheckRunning -- No --> NotRunning --> SetRunning --> ReturnStart
CheckRunning -- Yes --> ReturnStart
%% stop flow
StopCall --> CheckRunningStop
CheckRunningStop -- Yes --> SetStoppedAt --> SetNotRunning --> ReturnStop
CheckRunningStop -- No --> ReturnStop
%% elapsed_ms flow
GetElapsed --> StartedNone
StartedNone -- Yes --> ReturnZero
StartedNone -- No --> RunningCheck
RunningCheck -- Yes --> GetNow --> CalcElapsed
RunningCheck -- No --> UseStoppedAt --> CalcElapsed
%% reset flow
ResetCall --> ClearStarted --> ClearStopped --> ClearRunning