Files
babymonitor/backend/app/utils/time_utils.py
T
2026-04-24 08:02:13 +02:00

65 lines
2.1 KiB
Python

from datetime import datetime, time, timedelta
from typing import List
def get_day_night_splits(
session_start: datetime,
session_end: datetime,
day_start_boundary: time,
day_end_boundary: time,
) -> List[dict]:
"""
Splits a sleep session into day and night segments based on boundaries.
A segment is defined by [segment_start, segment_end] and its type (day/night).
"""
segments = []
points = [session_start, session_end]
for offset in [0, 1]:
base_date = session_start.date() + timedelta(days=offset)
try:
b1 = datetime.combine(base_date, day_start_boundary).replace(
tzinfo=session_start.tzinfo
)
b2 = datetime.combine(base_date, day_end_boundary).replace(
tzinfo=session_start.tzinfo
)
if session_start < b1 < session_end:
points.append(b1)
if session_start < b2 < session_end:
points.append(b2)
except (ValueError, AttributeError):
continue
sorted_points = sorted(list(set(points)))
for i in range(len(sorted_points) - 1):
seg_start = sorted_points[i]
seg_end = sorted_points[i + 1]
midpoint = seg_start + (seg_end - seg_start) / 2
is_day = day_start_pattern(
midpoint.time(), day_start_boundary, day_end_boundary
)
segments.append(
{"start": seg_start, "end": seg_end, "type": "day" if is_day else "night"}
)
return segments
def day_start_pattern(current_time: time, start: time, end: time) -> bool:
if start <= end:
return start <= current_time < end
else: # Spans midnight
return current_time >= start or current_time < end
from datetime import datetime, time, timedelta
def minutes_after(dt: datetime, reference: time) -> float:
"""Returns minutes after a reference time."""
ref_delta = timedelta(hours=reference.hour, minutes=reference.minute)
dt_delta = timedelta(hours=dt.hour, minutes=dt.minute)
return (dt_delta - ref_delta).total_seconds() / 60.0