Coverage for src/sensai/util/time.py: 34%
41 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-13 22:17 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-13 22:17 +0000
1from datetime import time
2from typing import TYPE_CHECKING
4if TYPE_CHECKING:
5 import pandas as pd
8def ts_next_month(ts: "pd.Timestamp") -> "pd.Timestamp":
9 m = ts.month
10 if m == 12:
11 return ts.replace(year=ts.year+1, month=1)
12 else:
13 return ts.replace(month=m+1)
16def time_of_day(ts: "pd.Timestamp") -> float:
17 """
18 :param ts: the timestamp
19 :return: the time of day as a floating point number in [0, 24)
20 """
21 return ts.hour + ts.minute / 60
24class TimeInterval:
25 def __init__(self, start: "pd.Timestamp", end: "pd.Timestamp"):
26 self.start = start
27 self.end = end
29 def contains(self, t: "pd.Timestamp"):
30 return self.start <= t <= self.end
32 def contains_time(self, t: time):
33 """
34 :param t: a time of day
35 :return: True iff the time interval contains the given time of day at least once, False otherwise
36 """
37 if (self.end - self.start).total_seconds() >= (60 * 60 * 24):
38 return True
39 return self.contains(self.start.replace(hour=t.hour, minute=t.minute, second=t.second, microsecond=t.microsecond)) or \
40 self.contains(self.end.replace(hour=t.hour, minute=t.minute, second=t.second, microsecond=t.microsecond))
42 def overlaps_with(self, other: "TimeInterval") -> bool:
43 other_ends_before = other.end <= self.start
44 other_starts_after = other.start >= self.end
45 return not (other_ends_before or other_starts_after)
47 def intersection(self, other: "TimeInterval") -> "TimeInterval":
48 return TimeInterval(max(self.start, other.start), min(self.end, other.end))
50 def time_delta(self) -> "pd.Timedelta":
51 return self.end - self.start
53 def mid_timestamp(self) -> "pd.Timestamp":
54 midTime: pd.Timestamp = self.start + 0.5 * self.time_delta()
55 return midTime
58def format_duration(seconds: float):
59 if seconds < 60:
60 return f"{seconds:.1f} seconds"
61 elif seconds < 3600:
62 minutes, secs = divmod(seconds, 60)
63 return f"{int(minutes)} minutes, {secs:.1f} seconds"
64 else:
65 hours, remainder = divmod(seconds, 3600)
66 minutes, secs = divmod(remainder, 60)
67 return f"{int(hours)} hours, {int(minutes)} minutes, {secs:.1f} seconds"