Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

Statistics collection query first result returned is wrong

I'm reading hourly statistics from HealthKit using executeStatisticsCollectionQuery (code below).

Expectation

What I expect is to get back the list with one row per hour, where each hours has the same cumulative sum value.

Actual result

In results, first hour always contains less calories than next hours, which all have the same value.

Example:

Start: 2025-06-02T00:00:00+03:00, anchor:  2025-06-02T00:00:00+03:00, end: 2025-06-02T12:00:00+03:00

🟡 2025-06-02T00:00:00+03:00 Optional(50.3986 kcal)
🟡 2025-06-02T01:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T02:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T03:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T04:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T05:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T06:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T07:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T08:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T09:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T10:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T11:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T12:00:00+03:00 Optional(14.0224 kcal)

As you can see, here we have 2025-06-02T00:00:00+03:00 Optional(50.3986 kcal)

Now, if I add one more hour to the request (from beginning of time window), the same hour has proper calories count, while newly added hour, has wrong value):

2025-06-01T23:00:00+03:00, anchor:  2025-06-01T23:00:00+03:00, end: 2025-06-02T12:00:00+03:00.

🟡 2025-06-01T23:00:00+03:00 Optional(50.3986 kcal)
🟡 2025-06-02T00:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T01:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T02:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T03:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T04:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T05:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T06:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T07:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T08:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T09:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T10:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T11:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T12:00:00+03:00 Optional(14.0224 kcal)

And now first hour of the day, magically has more calories burned: 2025-06-02T00:00:00+03:00 Optional(64.421 kcal)

I suspect similar things happen with other quantity types, but haven't yet found a way to reproduce it.

Am I doing something wrong or is it a bug in HealthKit?

Code

let anchorDate = startDate
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: [.strictStartDate])



healthStore.executeStatisticsCollectionQuery(
                quantityType: .basalEnergyBurned,
                quantitySamplePredicate: predicate,
                options: [.separateBySource, .cumulativeSum],
                anchorDate: anchorDate,
                intervalComponents: DateComponents(hour: 1),
                initialResultsHandler: { statistics, error in
                    if let error = error {
                        log(.error, "Error retrieving steps: \(error.localizedDescription)")
                        continuation.resume(throwing: SpikeException("Error retrieving steps: \(error.localizedDescription)"))
                        return
                    }
                    if let statistics {
                        let f = ISO8601DateFormatter()
                        f.timeZone = TimeZone.current
                        for s in statistics {
                            log(.debug, "\(f.string(from: s.startDate)) \(s.sumQuantity())")
                        }
                    }
                    continuation.resume(returning: statistics ?? [])
                }
            )

Sorry, forgot to mention example is for basal energy burned, which should always return the same number for any hour in a day. But I suspect that the same bug may be there with other types, it's just much harder to reproduce it.

Statistics collection query first result returned is wrong
 
 
Q