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.

@Jaroslav_the_healthy

My guess is that this is due to your predicate options. Play with the .strictStartDate and .strictEndDate.

As an experiment, change from .strictStartDate to .strictEndDate and see if the issue goes to the tail of the data instead.

Look at the actual basal samples saved in health kit near the hour mark and I bet you will find some that are overlapping before and after the hour. At least that is where I would start looking.

Statistics collection query first result returned is wrong
 
 
Q