Created
September 15, 2024 10:50
-
-
Save sqdnoises/dce6053e150447f41bce39fae9141527 to your computer and use it in GitHub Desktop.
Stopwatch - A solution to a problem that never existed...
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import time | |
| import datetime | |
| from typing import Any, Iterable | |
| __all__ = ( | |
| "Time", | |
| "DatetimeTime", | |
| "Stopwatch" | |
| ) | |
| class Time: | |
| """ | |
| A class to represent time intervals in seconds and nanoseconds. | |
| Attributes: | |
| start (float | None): Start time in seconds. | |
| end (float | None): End time in seconds. | |
| total (float | None): Total time interval in seconds. | |
| start_ns (int | None): Start time in nanoseconds. | |
| end_ns (int | None): End time in nanoseconds. | |
| total_ns (int | None): Total time interval in nanoseconds. | |
| """ | |
| start: float | None | |
| end: float | None | |
| total: float | None | |
| start_ns: int | None | |
| end_ns: int | None | |
| total_ns: int | None | |
| def __init__( | |
| self, | |
| start: int | float | None = None, | |
| end: int | float | None = None, | |
| ns: bool = False | |
| ) -> None: | |
| """ | |
| Initializes the Time object. | |
| Args: | |
| start (int | float | None): Start time in seconds or nanoseconds. | |
| end (int | float | None): End time in seconds or nanoseconds. | |
| ns (bool): If True, interpret start and end times as nanoseconds; otherwise, interpret as seconds. | |
| """ | |
| if ns: | |
| start = int(start) if start is not None else None | |
| end = int(end) if end is not None else None | |
| self.start_ns = 0 if start is None and end is not None else start | |
| self.end_ns = end | |
| self.start = self.convert_ns_to_s(self.start_ns) if self.start_ns is not None else None | |
| self.end = self.convert_ns_to_s(self.end_ns) if self.end_ns is not None else None | |
| else: | |
| start = float(start) if start is not None else None | |
| end = float(end) if end is not None else None | |
| self.start = 0.0 if start is None and end is not None else start | |
| self.end = end | |
| self.start_ns = self.convert_s_to_ns(self.start) if self.start is not None else None | |
| self.end_ns = self.convert_s_to_ns(self.end) if self.end is not None else None | |
| if self.start_ns is not None and self.end_ns is not None: | |
| self.total_ns = self.end_ns - self.start_ns | |
| self.total = self.convert_ns_to_s(self.total_ns) | |
| else: | |
| self.total_ns = None | |
| self.total = None | |
| def convert_ns_to_s(self, time_ns: int) -> float: | |
| """ | |
| Converts nanoseconds to seconds. | |
| Args: | |
| time_ns (int): Time in nanoseconds. | |
| Returns: | |
| float: Time in seconds. | |
| """ | |
| return time_ns / 1_000_000_000 | |
| def convert_s_to_ns(self, time_s: float) -> int: | |
| """ | |
| Converts seconds to nanoseconds. | |
| Args: | |
| time_s (float): Time in seconds. | |
| Returns: | |
| int: Time in nanoseconds. | |
| """ | |
| return int(time_s * 1_000_000_000) | |
| class DatetimeTime: | |
| """ | |
| A class to represent time intervals using datetime objects. | |
| Attributes: | |
| start (datetime.datetime | None): Start time as a datetime object. | |
| end (datetime.datetime | None): End time as a datetime object. | |
| total (datetime.timedelta | None): Total time interval as a timedelta object. | |
| """ | |
| start: datetime.datetime | None | |
| end: datetime.datetime | None | |
| total: datetime.timedelta | None | |
| def __init__( | |
| self, | |
| start: datetime.datetime | None = None, | |
| end: datetime.datetime | None = None | |
| ) -> None: | |
| """ | |
| Initializes the DatetimeTime object. | |
| Args: | |
| start (datetime.datetime | None): Start time as a datetime object. | |
| end (datetime.datetime | None): End time as a datetime object. | |
| """ | |
| self.start = start | |
| self.end = end | |
| if self.start is not None and self.end is not None: | |
| self.total = self.end - self.start | |
| else: | |
| self.total = None | |
| class Stopwatch: | |
| """ | |
| A class to measure elapsed time using either seconds and nanoseconds or datetime objects. | |
| Attributes: | |
| time (Time | DatetimeTime): Object to track time intervals. | |
| _return_ns (bool): If True, return time in nanoseconds; otherwise, return in seconds or timedelta. | |
| _dnargs (Iterable[Any]): Arguments for datetime.now() if using DatetimeTime. | |
| _dnkwargs (dict[str, Any]): Keyword arguments for datetime.now() if using DatetimeTime. | |
| """ | |
| time: Time | DatetimeTime | |
| _return_ns: bool | |
| _dnargs: Iterable[Any] | |
| _dnkwargs: dict[str, Any] | |
| def __init__( | |
| self, | |
| start: bool = False, | |
| *, | |
| return_ns: bool = False, | |
| datetime_: bool = False, | |
| datetime_now_args: Iterable[Any] = (), | |
| datetime_now_kwargs: dict[str, Any] = {} | |
| ) -> None: | |
| """ | |
| Initializes the Stopwatch object. | |
| Args: | |
| start (bool): If True, the stopwatch will start automatically upon initialization by calling `self.start()`. Defaults to False. | |
| return_ns (bool): If True, return elapsed time in nanoseconds; otherwise, return in seconds or timedelta. | |
| datetime_ (bool): If True, use datetime for time measurement; otherwise, use seconds and nanoseconds. | |
| datetime_now_args (Iterable[Any]): Arguments for datetime.now() if using DatetimeTime. | |
| datetime_now_kwargs (dict[str, Any]): Keyword arguments for datetime.now() if using DatetimeTime. | |
| """ | |
| if datetime_: | |
| self.time = DatetimeTime() | |
| self._dnargs = datetime_now_args | |
| self._dnkwargs = datetime_now_kwargs | |
| return | |
| self.time = Time() | |
| self._return_ns = return_ns | |
| if start: | |
| self.start() | |
| def start(self) -> None: | |
| """ | |
| Starts the stopwatch. Records the current time as the start time. | |
| """ | |
| if isinstance(self.time, DatetimeTime): | |
| self.time.start = datetime.datetime.now(*self._dnargs, **self._dnkwargs) | |
| return | |
| self.time.start_ns = time.monotonic_ns() | |
| self.time.start = self.time.convert_ns_to_s(self.time.start_ns) | |
| def stop(self) -> int | float | datetime.timedelta: | |
| """ | |
| Stops the stopwatch. Records the current time as the end time and calculates the elapsed time. | |
| Returns: | |
| int | float | datetime.timedelta: Elapsed time in nanoseconds, seconds, or timedelta. | |
| Raises: | |
| ValueError: If the stopwatch has not been started. | |
| """ | |
| if self.time.start is None: | |
| raise ValueError("Stopwatch has not been started.") | |
| if isinstance(self.time, DatetimeTime): | |
| self.time.end = datetime.datetime.now(*self._dnargs, **self._dnkwargs) | |
| self.time.total = self.time.end - self.time.start | |
| return self.time.total | |
| if self.time.start_ns is None: | |
| raise ValueError("Stopwatch has not been started.") | |
| self.time.end_ns = time.monotonic_ns() | |
| self.time.end = self.time.convert_ns_to_s(self.time.end_ns) | |
| self.time.total_ns = self.time.end_ns - self.time.start_ns | |
| self.time.total = self.time.end - self.time.start | |
| if self._return_ns: return self.time.total_ns | |
| else: return self.time.total |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment