diff --git a/LoopFollow/Stats/AggregatedStatsView.swift b/LoopFollow/Stats/AggregatedStatsView.swift index 35dfeb29d..951e0b230 100644 --- a/LoopFollow/Stats/AggregatedStatsView.swift +++ b/LoopFollow/Stats/AggregatedStatsView.swift @@ -24,14 +24,9 @@ struct AggregatedStatsView: View { _showGMI = State(initialValue: Storage.shared.showGMI.value) _showStdDev = State(initialValue: Storage.shared.showStdDev.value) - let calendar = dateTimeUtils.displayCalendar() - let startOfToday = calendar.startOfDay(for: Date()) - let end = calendar.date(byAdding: .second, value: -1, to: startOfToday) ?? Date() - let endDay = calendar.startOfDay(for: end) - let startDay = calendar.date(byAdding: .day, value: -7, to: endDay) ?? endDay - let start = calendar.startOfDay(for: startDay) - _startDate = State(initialValue: start) - _endDate = State(initialValue: end) + let range = StatsDateRange.lastComplete(days: 7) + _startDate = State(initialValue: range.start) + _endDate = State(initialValue: range.end) } var body: some View { diff --git a/LoopFollow/Stats/AggregatedStatsViewModel.swift b/LoopFollow/Stats/AggregatedStatsViewModel.swift index 005de2f41..253352e48 100644 --- a/LoopFollow/Stats/AggregatedStatsViewModel.swift +++ b/LoopFollow/Stats/AggregatedStatsViewModel.swift @@ -39,9 +39,8 @@ class AggregatedStatsViewModel: ObservableObject { } func updatePeriod(_ days: Int, completion: @escaping () -> Void = {}) { - let endDate = Date() - let startDate = dateTimeUtils.displayCalendar().date(byAdding: .day, value: -days, to: endDate) ?? endDate - updateDateRange(start: startDate, end: endDate, completion: completion) + let range = StatsDateRange.lastComplete(days: days) + updateDateRange(start: range.start, end: range.end, completion: completion) } func updateDateRange(start: Date, end: Date, completion: @escaping () -> Void = {}) { diff --git a/LoopFollow/Stats/DateRangePicker.swift b/LoopFollow/Stats/DateRangePicker.swift index 5bc9c334f..8b15e10d1 100644 --- a/LoopFollow/Stats/DateRangePicker.swift +++ b/LoopFollow/Stats/DateRangePicker.swift @@ -31,13 +31,13 @@ struct DateRangePicker: View { private var dayCount: Int { let calendar = dateTimeUtils.displayCalendar() - return calendar.dateComponents([.day], from: startDate, to: endDate).day ?? 0 + let startDay = calendar.startOfDay(for: startDate) + let endDay = calendar.startOfDay(for: endDate) + return (calendar.dateComponents([.day], from: startDay, to: endDay).day ?? 0) + 1 } private var lastFullDay: Date { - let calendar = dateTimeUtils.displayCalendar() - let startOfToday = calendar.startOfDay(for: Date()) - return calendar.date(byAdding: .second, value: -1, to: startOfToday) ?? Date() + StatsDateRange.lastComplete(days: 1).end } var body: some View { @@ -238,11 +238,9 @@ struct DateRangePicker: View { } private func setDateRange(days: Int) { - let calendar = dateTimeUtils.displayCalendar() - endDate = lastFullDay - let endDayStart = calendar.startOfDay(for: endDate) - let startDayStart = calendar.date(byAdding: .day, value: -days, to: endDayStart) ?? endDayStart - startDate = calendar.startOfDay(for: startDayStart) + let range = StatsDateRange.lastComplete(days: days) + startDate = range.start + endDate = range.end showStartDatePicker = false showEndDatePicker = false onDateChange() diff --git a/LoopFollow/Stats/SimpleStatsViewModel.swift b/LoopFollow/Stats/SimpleStatsViewModel.swift index 960e17c57..a3b97f1d1 100644 --- a/LoopFollow/Stats/SimpleStatsViewModel.swift +++ b/LoopFollow/Stats/SimpleStatsViewModel.swift @@ -66,7 +66,7 @@ class SimpleStatsViewModel: ObservableObject { let smbTotal = smbInPeriod.reduce(0.0) { $0 + $1.value } let totalBolusInPeriod = bolusTotal + smbTotal - let cutoffTime = Date().timeIntervalSince1970 - (Double(dataService.daysToAnalyze) * 24 * 60 * 60) + let cutoffTime = dataService.startDate.timeIntervalSince1970 let allBolusDates = (bolusesInPeriod + smbInPeriod).map { $0.date }.filter { $0 >= cutoffTime } let actualDays = calculateActualDaysCovered(dates: allBolusDates, requestedDays: dataService.daysToAnalyze) @@ -93,7 +93,7 @@ class SimpleStatsViewModel: ObservableObject { let totalCarbsInPeriod = dailyCarbs.values.reduce(0.0, +) - let daysWithData = max(dailyCarbs.count, 1) + let daysWithData = dataService.daysToAnalyze if daysWithData > 0 { avgCarbs = totalCarbsInPeriod / Double(daysWithData) @@ -295,7 +295,7 @@ class SimpleStatsViewModel: ObservableObject { guard !dates.isEmpty else { return requestedDays } let calendar = dateTimeUtils.displayCalendar() - let cutoffTime = Date().timeIntervalSince1970 - (Double(requestedDays) * 24 * 60 * 60) + let cutoffTime = dataService.startDate.timeIntervalSince1970 let filteredDates = dates.filter { $0 >= cutoffTime } var uniqueDays = Set() diff --git a/LoopFollow/Stats/StatsDataService.swift b/LoopFollow/Stats/StatsDataService.swift index 80ea66b54..4aa5b7c7f 100644 --- a/LoopFollow/Stats/StatsDataService.swift +++ b/LoopFollow/Stats/StatsDataService.swift @@ -32,9 +32,11 @@ class StatsDataService { func updateDateRange(start: Date, end: Date) { startDate = start endDate = end - // Also update daysToAnalyze for compatibility with existing code - let daysBetween = dateTimeUtils.displayCalendar().dateComponents([.day], from: start, to: end).day ?? 14 - daysToAnalyze = max(daysBetween, 1) + let calendar = dateTimeUtils.displayCalendar() + let startDay = calendar.startOfDay(for: start) + let endDay = calendar.startOfDay(for: end) + let daysBetween = calendar.dateComponents([.day], from: startDay, to: endDay).day ?? 13 + daysToAnalyze = daysBetween + 1 } func ensureDataAvailable(onProgress: @escaping () -> Void, completion: @escaping () -> Void) { diff --git a/LoopFollow/Stats/StatsDateRange.swift b/LoopFollow/Stats/StatsDateRange.swift new file mode 100644 index 000000000..e2e00458b --- /dev/null +++ b/LoopFollow/Stats/StatsDateRange.swift @@ -0,0 +1,17 @@ +// LoopFollow +// StatsDateRange.swift + +import Foundation + +enum StatsDateRange { + /// Returns start/end dates for the last complete N-day period. + /// End is 23:59:59 of yesterday; start is 00:00:00 of the day N days back. + static func lastComplete(days: Int) -> (start: Date, end: Date) { + let calendar = dateTimeUtils.displayCalendar() + let startOfToday = calendar.startOfDay(for: Date()) + let end = calendar.date(byAdding: .second, value: -1, to: startOfToday) ?? Date() + let endDayStart = calendar.startOfDay(for: end) + let start = calendar.date(byAdding: .day, value: -(days - 1), to: endDayStart) ?? endDayStart + return (start: calendar.startOfDay(for: start), end: end) + } +}