65 lines
2.1 KiB
Python
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
|