You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HKStatisticsCollectionQuery仅返回近一周数据,其余日期显示nil的问题

问题:HKStatisticsCollectionQuery查询30天爬楼数据仅近一周有效,其余日期返回nil

我通过HKStatisticsCollectionQuery查询过去30天的HKQuantityTypeIdentifier.flightsClimbed数据,已确认目标日期均存在数据,但打印结果时仅最近一周的数据正常,剩余23天全部返回nil。

查询代码

func makeElevationQuery(completion: @escaping (HKStatisticsCollection?) -> ()) {
            
    let elevationType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.flightsClimbed)!
            
    let calendar = NSCalendar.current
    
    let endDate = Date()
    
    let startDate = calendar.date(byAdding: .day, value: -30, to: endDate)
    
    let anchorDate = Date.mondayAt12AM()
    
    let daily = DateComponents(day : 1)
    
    let summariesWithinRange = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
    
    elevationQuery = HKStatisticsCollectionQuery(quantityType: elevationType, quantitySamplePredicate: summariesWithinRange, options: .cumulativeSum, anchorDate: anchorDate, intervalComponents: daily)
    
    elevationQuery!.initialResultsHandler = {elevationQuery, statisticsCollection, error in
        completion(statisticsCollection)
    }
    
    healthstore.execute(elevationQuery!)
    
}
}


extension Date {
    static func mondayAt12AM() -> Date {
        return Calendar(identifier: .iso8601).date(from: Calendar(identifier: .iso8601).dateComponents([.yearForWeekOfYear, .weekOfYear], from: Date()))!
    }
}

ContentView代码

struct ContentView: View {
    @StateObject var fitness = main()
    @State var final = HKActivitySummary()
    @State var MonthElevation = HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.flightsClimbed)
    
    var body: some View {
        Button("refresh"){
            fitness.authorizeHealthkit()
            fitness.makeQuery() { (summary) in
                final = summary
                fitness.makeElevationQuery { statisticsCollection in
                    if let statisticsCollection = statisticsCollection {
                        let startDate = Calendar.current.date(byAdding: .day, value: -30, to: Date())
                        let endDate = Date()
                        statisticsCollection.enumerateStatistics(from: startDate!, to: endDate) {
                            (statistics, stop) in
                            
                            let count = statistics.sumQuantity()?.doubleValue(for: .count())
                            print(count) //仅最近一周数据正常,其余23天打印nil
                        }
                    }
                        
                }
            }
        }
    }
}

问题原因

问题出在锚点日期(anchorDate)的设置:

  1. 当前mondayAt12AM()使用ISO8601日历锚定到当前周的周一零点,而HKStatisticsCollectionQuery的统计区间是基于锚点日期向后/向前按intervalComponents(这里是1天)划分的。当查询30天数据时,前23天的区间无法和自然日对齐,导致统计不到对应数据。
  2. 混用了NSCalendar.current和ISO8601日历,可能导致日期计算出现偏差。

解决方法

1. 修改锚点日期为查询起始日的零点

将锚点日期设置为查询起始日期当天的零点,确保所有统计区间和自然日完全对齐,同时统一使用系统默认日历Calendar.current。

修改Date扩展方法:

extension Date {
    static func startOfDay(for date: Date) -> Date {
        return Calendar.current.startOfDay(for: date)
    }
}

2. 更新查询代码中的锚点设置

func makeElevationQuery(completion: @escaping (HKStatisticsCollection?) -> ()) {
    let elevationType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.flightsClimbed)!
    let calendar = Calendar.current
    
    let endDate = Date()
    // 强制解包前建议做非空判断,这里为了保持原有逻辑简化处理
    let startDate = calendar.date(byAdding: .day, value: -30, to: endDate)!
    // 锚点设为查询起始日的零点
    let anchorDate = Date.startOfDay(for: startDate)
    let daily = DateComponents(day: 1)
    
    let summariesWithinRange = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
    
    elevationQuery = HKStatisticsCollectionQuery(
        quantityType: elevationType,
        quantitySamplePredicate: summariesWithinRange,
        options: .cumulativeSum,
        anchorDate: anchorDate,
        intervalComponents: daily
    )
    
    elevationQuery!.initialResultsHandler = { query, statisticsCollection, error in
        completion(statisticsCollection)
    }
    
    healthstore.execute(elevationQuery!)
}

3. 优化结果枚举(可选)

在枚举统计结果时加上日期打印,方便验证每个日期的数据:

statisticsCollection.enumerateStatistics(from: startDate!, to: endDate) { statistics, stop in
    let date = Calendar.current.startOfDay(for: statistics.startDate)
    let count = statistics.sumQuantity()?.doubleValue(for: .count())
    print("\(date): \(count ?? 0)")
}

内容的提问来源于stack exchange,提问作者Eddie Gabriel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 08:57:14