Skip to content

Fix Health Connect "startTime must be before endTime" crash at day boundary#1

Merged
air17 merged 2 commits into
masterfrom
copilot/fix-steps-count-error
May 12, 2026
Merged

Fix Health Connect "startTime must be before endTime" crash at day boundary#1
air17 merged 2 commits into
masterfrom
copilot/fix-steps-count-error

Conversation

Copilot AI commented May 12, 2026

Copy link
Copy Markdown
Contributor

Two independent time reads in todayRange() created a race where LocalDate.now() could tick to the next day while Instant.now() still held a timestamp from the previous millisecond, making startOfDay > now and causing every Health Connect query to fail.

  • Single clock snapshot — derive startOfDay from one Instant.now() call instead of two separate time reads
  • Unconditional end-bound clamp — use maxOf(now, startOfDay.plusSeconds(1)) to guarantee a strictly non-empty interval regardless of clock skew or DST transitions
private fun todayRange(): Pair<Instant, Instant> {
    val zone = ZoneId.systemDefault()
    val now = Instant.now()
    val startOfDay = now.atZone(zone).toLocalDate().atStartOfDay(zone).toInstant()
    val endTime = maxOf(now, startOfDay.plusSeconds(1))
    return startOfDay to endTime
}

@air17 air17 marked this pull request as ready for review May 12, 2026 17:08
Copilot AI review requested due to automatic review settings May 12, 2026 17:08
@air17

air17 commented May 12, 2026

Copy link
Copy Markdown
Owner

@copilot can you check if this fixes the error Error: startTime must be before endTime. And if something else is necessary to do

Copilot AI commented May 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot can you check if this fixes the error Error: startTime must be before endTime. And if something else is necessary to do

Yes, the fix fully addresses the startTime must be before endTime error.

Root cause: The original todayRange() made two independent time reads — LocalDate.now() and Instant.now() — at slightly different clock ticks. At midnight exactly, LocalDate.now() could already return the new day (giving startOfDay = midnight) while Instant.now() still held a timestamp from the previous millisecond, so startOfDay > now → Health Connect rejected the query.

What the fix does (lines 166–172):

  1. Single clock snapshotInstant.now() is called once; startOfDay is derived from that same instant, eliminating the race.
  2. Hard lower-bound clampmaxOf(now, startOfDay.plusSeconds(1)) guarantees endTime > startOfDay even under DST transitions or any remaining clock skew.

Every TimeRangeFilter.between call in the whole codebase goes through this one todayRange() helper, so all five call sites are covered. Nothing else needs to change.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a Health Connect crash at the day boundary by ensuring todayRange() always returns a strictly non-empty time window derived from a single clock snapshot, preventing TimeRangeFilter.between(start, end) from receiving an invalid interval.

Changes:

  • Compute startOfDay from a single Instant.now() snapshot (avoids the LocalDate.now() / Instant.now() race).
  • Guarantee endTime > startOfDay via an end-bound clamp (maxOf(now, startOfDay.plusSeconds(1))).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot finished work on behalf of air17 May 12, 2026 17:11
Copilot AI requested a review from air17 May 12, 2026 17:11
@air17 air17 merged commit e599a99 into master May 12, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants