From 3fe147247e9fe3f14b250bf7643c59352092289c Mon Sep 17 00:00:00 2001 From: Gideon Zenz Date: Sun, 4 Jan 2026 14:47:46 +0100 Subject: [PATCH] Fix last sample sync issue by making slice boundaries inclusive Changed boundary checks from exclusive [start, end) to inclusive [start, end] to ensure samples occurring exactly at slice boundaries are synced correctly. This fixes the issue where the last sample in the database would never get synced because it was filtered out by the exclusive end boundary check while the sync state advanced to its timestamp. Affected syncers: - AbstractTimeSampleSyncer (HRV, SpO2, Weight, etc.) - StepsSyncer - HeartRateSyncer - SleepSyncer --- .../util/healthconnect/syncers/AbstractTimeSampleSyncer.kt | 3 ++- .../gadgetbridge/util/healthconnect/syncers/HeartRateSync.kt | 4 ++-- .../gadgetbridge/util/healthconnect/syncers/SleepSyncer.kt | 5 +++-- .../gadgetbridge/util/healthconnect/syncers/StepsSync.kt | 5 +++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractTimeSampleSyncer.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractTimeSampleSyncer.kt index 493825ca30..cef7e0c3b9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractTimeSampleSyncer.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/AbstractTimeSampleSyncer.kt @@ -102,7 +102,8 @@ internal abstract class AbstractTimeSampleSyncer sliceEnd OR sessionEnd < sliceStart + if (sessionBoundaryStart.isAfter(sliceEndBoundary) || sessionBoundaryEndInclusive.isBefore(sliceStartBoundary)) { LOG.debug( "Skipping sleep session (identified by SleepAnalysis) for device '{}' (Timeframe: {} to {}) as it does not overlap with current slice ({} to {}).", deviceName, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/StepsSync.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/StepsSync.kt index 44ce1c12a3..7970b6ee09 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/StepsSync.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/healthconnect/syncers/StepsSync.kt @@ -69,8 +69,9 @@ internal object StepsSyncer : ActivitySampleSyncer { val endTs = Instant.ofEpochSecond(currentSample.timestamp.toLong()) val startTs = endTs.minus(1, ChronoUnit.MINUTES) - // Ensure the record's interval [startTs, endTs) overlaps with the slice [sliceStartBoundary, sliceEndBoundary) - if (endTs.isAfter(sliceStartBoundary) && startTs.isBefore(sliceEndBoundary)) { + // Use inclusive boundaries [sliceStart, sliceEnd] for the slice + // Overlap check: interval overlaps if endTs > sliceStart AND startTs <= sliceEnd + if (endTs.isAfter(sliceStartBoundary) && !startTs.isAfter(sliceEndBoundary)) { stepsRecordList.add(StepsRecord(startTs, offset, endTs, offset, stepsInMinute, metadata)) } else { skippedCount++