fix: sleep import groups segments by gap instead of date boundary
Problem: Segments crossing midnight were split into different nights - 22:30-23:15 (21.03) → assigned to 21.03 - 00:30-02:45 (22.03) → assigned to 22.03 But both belong to the same night (21/22.03)! Solution: Gap-based grouping - Sort segments chronologically - Group segments with gap < 2 hours - Night date = wake_time.date() (last segment's end date) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b1a92c01fc
commit
9a9c597187
|
|
@ -484,13 +484,20 @@ async def import_apple_health_sleep(
|
||||||
'phase': phase_en
|
'phase': phase_en
|
||||||
})
|
})
|
||||||
|
|
||||||
# Group by night (wake date)
|
# Sort segments chronologically
|
||||||
nights = {}
|
segments.sort(key=lambda s: s['start'])
|
||||||
for seg in segments:
|
|
||||||
wake_date = seg['end'].date() # Date of waking up
|
|
||||||
|
|
||||||
if wake_date not in nights:
|
# Group segments into nights (gap-based)
|
||||||
nights[wake_date] = {
|
# If gap between segments > 2 hours → new night
|
||||||
|
nights = []
|
||||||
|
current_night = None
|
||||||
|
|
||||||
|
for seg in segments:
|
||||||
|
# Start new night if:
|
||||||
|
# 1. First segment
|
||||||
|
# 2. Gap > 2 hours since last segment
|
||||||
|
if current_night is None or (seg['start'] - current_night['wake_time']).total_seconds() > 7200:
|
||||||
|
current_night = {
|
||||||
'bedtime': seg['start'],
|
'bedtime': seg['start'],
|
||||||
'wake_time': seg['end'],
|
'wake_time': seg['end'],
|
||||||
'segments': [],
|
'segments': [],
|
||||||
|
|
@ -499,21 +506,28 @@ async def import_apple_health_sleep(
|
||||||
'light_minutes': 0,
|
'light_minutes': 0,
|
||||||
'awake_minutes': 0
|
'awake_minutes': 0
|
||||||
}
|
}
|
||||||
|
nights.append(current_night)
|
||||||
|
|
||||||
night = nights[wake_date]
|
# Add segment to current night
|
||||||
night['segments'].append(seg)
|
current_night['segments'].append(seg)
|
||||||
night['wake_time'] = max(night['wake_time'], seg['end']) # Latest wake time
|
current_night['wake_time'] = max(current_night['wake_time'], seg['end'])
|
||||||
night['bedtime'] = min(night['bedtime'], seg['start']) # Earliest bed time
|
current_night['bedtime'] = min(current_night['bedtime'], seg['start'])
|
||||||
|
|
||||||
# Sum phases
|
# Sum phases
|
||||||
if seg['phase'] == 'deep':
|
if seg['phase'] == 'deep':
|
||||||
night['deep_minutes'] += seg['duration_min']
|
current_night['deep_minutes'] += seg['duration_min']
|
||||||
elif seg['phase'] == 'rem':
|
elif seg['phase'] == 'rem':
|
||||||
night['rem_minutes'] += seg['duration_min']
|
current_night['rem_minutes'] += seg['duration_min']
|
||||||
elif seg['phase'] == 'light':
|
elif seg['phase'] == 'light':
|
||||||
night['light_minutes'] += seg['duration_min']
|
current_night['light_minutes'] += seg['duration_min']
|
||||||
elif seg['phase'] == 'awake':
|
elif seg['phase'] == 'awake':
|
||||||
night['awake_minutes'] += seg['duration_min']
|
current_night['awake_minutes'] += seg['duration_min']
|
||||||
|
|
||||||
|
# Convert nights list to dict with wake_date as key
|
||||||
|
nights_dict = {}
|
||||||
|
for night in nights:
|
||||||
|
wake_date = night['wake_time'].date() # Date when you woke up
|
||||||
|
nights_dict[wake_date] = night
|
||||||
|
|
||||||
# Insert nights
|
# Insert nights
|
||||||
imported = 0
|
imported = 0
|
||||||
|
|
@ -522,7 +536,7 @@ async def import_apple_health_sleep(
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
|
|
||||||
for date, night in nights.items():
|
for date, night in nights_dict.items():
|
||||||
# Calculate total duration (sum of all phases)
|
# Calculate total duration (sum of all phases)
|
||||||
duration_minutes = (
|
duration_minutes = (
|
||||||
night['deep_minutes'] +
|
night['deep_minutes'] +
|
||||||
|
|
@ -593,6 +607,6 @@ async def import_apple_health_sleep(
|
||||||
return {
|
return {
|
||||||
"imported": imported,
|
"imported": imported,
|
||||||
"skipped": skipped,
|
"skipped": skipped,
|
||||||
"total_nights": len(nights),
|
"total_nights": len(nights_dict),
|
||||||
"message": f"{imported} Nächte importiert, {skipped} übersprungen (manuelle Einträge)"
|
"message": f"{imported} Nächte importiert, {skipped} übersprungen (manuelle Einträge)"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user