Calculate Asleep time in HealthKit using Swift

流过昼夜 提交于 2020-11-29 19:15:30

问题


I have the following code that gets the sum of sleep hours. However, it is summing inbed and asleep together. What I am trying to get is a sum for just the asleep time.

func readSleepAnalysis(date: Date) {

    if let sleepType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.sleepAnalysis) {

        let startDate = convertSleepStartDate(StartDate: date)
        let endDate = convertSleepEndDate(EndDate: date)
        let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)

        let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)

        let query = HKSampleQuery(sampleType: sleepType, predicate: predicate, limit: 30, sortDescriptors: [sortDescriptor]) {
                                                    (query, samples, error) in

                                        guard
                                            error == nil,
                                        samples == samples as? [HKCategorySample] else {
                                                print("Something went wrong getting sleep analysis: \(String(describing: error))")
                                                return
                                        }

                                        let total = samples?.map(self.calculateSleepHours).reduce(0, {$0 + $1}) ?? 0
                                        DispatchQueue.main.async {
                                            self.userSleepMinutes = total
                                            print("userSleepHours = \(self.userSleepMinutes)")
                                        }

        }
        healthKit.execute(query)
    }
}

func calculateSleepHours(sample: HKSample) -> TimeInterval {

    let hours = sample.endDate.timeIntervalSince(sample.startDate) / 60 / 60

    return hours
}

I previously discovered that Apple records all data based on UTC. Make sense! However, this may work for active energy and other data like that but total sleep time can't be calculated like this. I am calculating the total time from 6 PM the night prior to 05:59 AM that day. Here is how I am doing that (there may be a better way but it's beyond me at this moment).

func convertSleepStartDate(StartDate: Date) -> Date {

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyy-MM-dd '18':'00':'01' +0000"
    let dateString = dateFormatter.string(from: StartDate)
    dateFormatter.dateFormat = "yyy-MM-dd HH:mm:ss +0000"
    let date = dateFormatter.date(from: dateString)
    let datePrior = Calendar.current.date(byAdding: .hour, value: -24, to: date!)
    print(datePrior as Any)

    return datePrior!
}

func convertSleepEndDate(EndDate: Date) -> Date {

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyy-MM-dd '17':'59':'59' +0000"
    let dateString = dateFormatter.string(from: EndDate)
    dateFormatter.dateFormat = "yyy-MM-dd HH:mm:ss +0000"
    let date = dateFormatter.date(from: dateString)
    print(date as Any)

    return date!
}

Any ideas?


回答1:


Better late than never: In your calculateSleepHours function, you should check sample.value against the HKCategoryValueSleepAnalysis constants (inBed, asleep, awake). That will tell you the interval's type. It will also teach you how Apple measures and returns this data. Keep an eye on the intervals, because when you hit the end of the planned sleep time on the watch, it will give you a summary of inBed time.

let value1 = (sample.value == HKCategoryValueSleepAnalysis.inBed.rawValue) ? "InBed" : "Asleep"
                    let value2 = (sample.value == HKCategoryValueSleepAnalysis.asleep.rawValue) ? "Asleep" : "Awake"
                    let value3 = (sample.value == HKCategoryValueSleepAnalysis.awake.rawValue) ? "Awake" : "Asleep"

The 3 values contain the type of constant that each interval is measuring. It is almost always asleep, but may differ depending on the Watch OS versions.

You can print the values and see, on a per interval basis, exactly what is being measured. Be sure to print the sample.startDate and sample.endDate too. That will teach you all you need to know to get actual sleep time between two Dates.



来源:https://stackoverflow.com/questions/61236981/calculate-asleep-time-in-healthkit-using-swift

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!