Fix cross-midnight adaptive dose creating false missed reminders
When adaptive timing shifts a late-night dose past midnight (e.g. 23:00 → 00:42), the scheduler would create a new pending schedule on the next day even if the dose was already taken. The proximity window was too narrow to match the take log against the shifted time. - Skip creating schedules for doses already taken/skipped (checks today + yesterday logs against base_time) - Fix midnight wraparound in proximity check for should_send_nag - Display base_time (actual dose time) in reminders instead of the internal adjusted_time Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -395,9 +395,11 @@ def should_send_nag(
|
||||
int(scheduled_time[:2]),
|
||||
int(scheduled_time[3:5]),
|
||||
)
|
||||
diff_minutes = abs(
|
||||
(log_hour * 60 + log_min) - (sched_hour * 60 + sched_min)
|
||||
)
|
||||
log_mins = log_hour * 60 + log_min
|
||||
sched_mins = sched_hour * 60 + sched_min
|
||||
diff_minutes = abs(log_mins - sched_mins)
|
||||
# Handle midnight wraparound (e.g. 23:00 vs 00:42)
|
||||
diff_minutes = min(diff_minutes, 1440 - diff_minutes)
|
||||
if diff_minutes <= proximity_window:
|
||||
return False, f"Already {action} today"
|
||||
|
||||
@@ -463,8 +465,33 @@ def create_daily_schedule(user_uuid: str, med_id: str, base_times: List[str], re
|
||||
# Calculate adjusted times
|
||||
adjusted_times = calculate_adjusted_times(user_uuid, base_times)
|
||||
|
||||
# Check recent med logs to skip doses already taken/skipped.
|
||||
# Handles cross-midnight: if adaptive offset shifts 23:00 → 00:42 today,
|
||||
# but the user already took the 23:00 dose last night, don't schedule it.
|
||||
user_tz = tz_for_user(user_uuid)
|
||||
yesterday = today - timedelta(days=1)
|
||||
recent_logs = postgres.select("med_logs", {"medication_id": med_id, "user_uuid": user_uuid})
|
||||
taken_base_times = set()
|
||||
for log in recent_logs:
|
||||
if log.get("action") not in ("taken", "skipped"):
|
||||
continue
|
||||
created_at = log.get("created_at")
|
||||
if not created_at:
|
||||
continue
|
||||
if created_at.tzinfo is None:
|
||||
created_at = created_at.replace(tzinfo=timezone.utc)
|
||||
log_date = created_at.astimezone(user_tz).date()
|
||||
if log_date not in (today, yesterday):
|
||||
continue
|
||||
log_sched = _normalize_time(log.get("scheduled_time"))
|
||||
if log_sched:
|
||||
taken_base_times.add(log_sched)
|
||||
|
||||
# Create schedule records for each time
|
||||
for base_time, (adjusted_time, offset) in zip(base_times, adjusted_times):
|
||||
if base_time in taken_base_times:
|
||||
continue
|
||||
|
||||
data = {
|
||||
"id": str(uuid.uuid4()),
|
||||
"user_uuid": user_uuid,
|
||||
|
||||
Reference in New Issue
Block a user