I'm reading user's health data using HealthKit. Trying to get the timezone information from Health data to identify on which exact timezone the health activity has happened. For this, I'm depending on 'HKMetadataKeyTimeZone' key from HealthKit metadata. But the value for 'HKMetadataKeyTimeZone' key is always nil even for the health data that is automatically recorded by Apple's Health app. Same problem for the data that is manually entered on Apple's Health app.
So is there any other key/way that can give the time zone information for each sample?
or Apple's health app is not at all logging the timezone's information for health data?
or Apple's health app is logging the timezone's information for health data and not giving it to developers via HealthKit framework?
The following blog post says, samples retrieved from HealthKit do not have time zone information associated with them, unless the creating application captures that information in the metadata property using the predefined HKMetadataKeyTimeZone key.
Even Apple fails to add the time zone metadata to samples generated through their own Health app.
http://www.openmhealth.org/3-painful-lessons-learned-building-with-healthkit/
Below is my code:
import HealthKit
let healthKitStore: HKHealthStore = HKHealthStore()
func getHealthDataValue_QuantityType(healthQuantityType : HKQuantityType?, strUnitType : String)
{
if let healthQuantityType = healthQuantityType {
if (HKHealthStore.isHealthDataAvailable()) {
let query = HKAnchoredObjectQuery(type: healthQuantityType, predicate: nil, anchor: nil, limit: Int(HKObjectQueryNoLimit)) { (query, newSamples, deletedSamples, newAnchor, error) -> Void in
guard let samples = newSamples as? [HKQuantitySample] else {
print("newSamples are nil, Error: \(error?.localizedDescription ?? "")\n, identifier: \(healthQuantityType.identifier)")
return
}
var healthKitData = [[String: Any]]()
for quantitySample in samples {
let quantity = quantitySample.quantity
let healthDataUnit : HKUnit
if (strUnitType.characters.count > 0 ) {
healthDataUnit = HKUnit(from: strUnitType)
} else {
healthDataUnit = HKUnit.count()
}
let tempActualhealthData = quantity.doubleValue(for: healthDataUnit)
var dicHealth = [String: Any]()
dicHealth["StartDate"] = quantitySample.startDate.epoch()
dicHealth["EndDate"] = quantitySample.endDate.epoch()
dicHealth["TimeZone"] = getTimeZoneString(sample: quantitySample)
dicHealth["Value"] = tempActualhealthData
dicHealth["Unit"] = strUnitType
dicHealth["Source"] = quantitySample.sourceRevision.source.name
dicHealth["WasUserEntered"] = quantitySample.metadata?["HKWasUserEntered"] as? Int
healthKitData.append(dicHealth)
}
print(healthKitData)
}
healthKitStore.execute(query)
}
}
}
extension Date {
func epoch(isMilliSeconds: Bool = false) -> UInt64 {
return UInt64(self.timeIntervalSince1970 * (isMilliSeconds ? 1000 : 1))
}
}
func getTimeZoneString(sample: HKSample? = nil, shouldReturnDefaultTimeZoneInExceptions: Bool = true) -> String? {
var timeZone: TimeZone?
print("sample?.metadata?[HKMetadataKeyTimeZone]: \(sample?.metadata?[HKMetadataKeyTimeZone])") // I have steps data recorded by my iPhone6s, not getting the timezone information for that health data.
if let metaDataTimeZoneValue = sample?.metadata?[HKMetadataKeyTimeZone] as? String {
timeZone = TimeZone(identifier: metaDataTimeZoneValue)
}
if shouldReturnDefaultTimeZoneInExceptions == true && timeZone == nil {
timeZone = TimeZone.current
}
var timeZoneString: String?
if let timeZone = timeZone {
let seconds = timeZone.secondsFromGMT()
let hours = seconds/3600
let minutes = abs(seconds/60) % 60
timeZoneString = String(format: "%+.2d:%.2d", hours, minutes)
}
return timeZoneString
}
var healthKitTypesToRead = Set<HKObjectType>()
if let stepCountObject = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount) {
healthKitTypesToRead.insert(stepCountObject)
}
healthKitStore.requestAuthorization(toShare: nil, read: healthKitTypesToRead) { (success, error) in
if error == nil {
getHealthDataValue_QuantityType(healthQuantityType: HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount), strUnitType: "count")
}
}