Set selected time in EKEvent - ios

In my application I can select date and time for EKEvent. I almost achieved what I want except Time. How can I set time. Below is my code, I have tried.
func setReminder(){
let eventStore = EKEventStore()
eventStore.requestAccess(
to: EKEntityType.event, completion: {(granted, error) in
if !granted {
print("Access to store not granted")
print(error!.localizedDescription)
} else {
print("Access granted")
let event = EKEvent(eventStore: eventStore)
event.title = self.getCategoryText + " Reminder"
event.calendar =
eventStore.defaultCalendarForNewEvents
event.timeZone = TimeZone.current
let alarm = EKAlarm(absoluteDate: self.selectedDate!)
event.addAlarm(alarm)
if self.daysBeforeDate != nil{
let earlierDate = self.daysBeforeDate
let earlierAlarm = EKAlarm(absoluteDate: earlierDate!)
event.addAlarm(earlierAlarm)
}
print("selected time", self.selectedTime)
var number1: Double = (self.selectedTime! as NSString).doubleValue
event.startDate = self.selectedDate!.addingTimeInterval(number1)
event.endDate = self.selectedDate!
do {
try eventStore.save(event, span: .thisEvent, commit: true)
} catch let error {
print("Reminder failed with error \(error.localizedDescription)")
return
}
}
})
}
Update 1
let calendar = Calendar.current
var dateComponents = DateComponents()
dateComponents.year = calendar.component(.year, from: self.selectedDate!)
dateComponents.month = calendar.component(.month, from: self.selectedDate!)
dateComponents.day = calendar.component(.day, from: self.selectedDate!)
dateComponents.timeZone = TimeZone.current
dateComponents.hour = self.selectedHour
dateComponents.minute = self.selectedMinute
let userCalendar = Calendar.current // user calendar
let someDateTime = userCalendar.date(from: dateComponents)

This is the code I've used for creating an event for a time interval and it's working fine for me:
func saveEvent(on date: Date, withTitle title: String, forHourse hourse: Int) {
let event = EKEvent(eventStore: eventStore!)
event.title = title
event.startDate = date
event.endDate = date.addingTimeInterval((TimeInterval(hourse * 60 * 60)))
let alarm = EKAlarm(absoluteDate: date)
event.alarms = [alarm]
event.calendar = (eventStore?.defaultCalendarForNewEvents)!
do {
try eventStore?.save(event, span: .thisEvent, commit: true)
} catch {
}
}

Related

decrement int from string time 4:01 to 3:51 in swift

hi I want to make a local notification from string time, I want the notification launch 10 minute before given time. I have trouble how to make the time from 4:01 into 3:51, please help. this is my code
let a = "4:01"
func startNoftification(prayer: String) {
let time = prayer.split(separator: ":").map { (x) -> Int in
return Int(String(x))!
}
let content = UNMutableNotificationContent()
content.title = "Adzan"
content.body = "it's time to sholat dzuhur"
let gregorian = Calendar(identifier: .gregorian)
var component = gregorian.dateComponents([.year, .month, .day, .hour, .minute, .second], from: Date())
component.hour = time[0]
component.minute = time[1] - 10
guard let date = gregorian.date(from: component) else { return }
let triggerDaily = Calendar.current.dateComponents([.hour, .minute, .second], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDaily, repeats: true)
let request = UNNotificationRequest(identifier: "Hijrah", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
if let err = error {
print("Notif error:", err)
return
}
}
}
Is this what you need?
let time = "4:01"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "hh:mm"
guard let date = dateFormatter.date(from: time) else {
return
}
let targetTime = Date(timeInterval: -(10 * 60), since: date) // Change time interval to required value in seconds
let targetTimeString = dateFormatter.string(from: targetTime)
print(targetTimeString) // Prints 3:51
Or if your countdown time has a lot of time components, use DateComponents.
var dateComponents = DateComponents()
dateComponents.minute = -10
// Other components
if let targetTime = Calendar.current.date(byAdding: dateComponents, to: date)
print(dateFormatter.string(from: targetTime))
}
Here I have solution combine with rakesha Shastri answer, hopefully it can helps others.
First import UserNotification in appDelegate and in your controller
import UserNotification
and add code for didFinishWithLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge]) { (granted, error) in
if let err = error {
print("Notifications permission denied because:", err)
return
}
if granted {
print("Notifications permission granted.")
}
}
}
and you can make a function and add string time parameters either from API or arbitrary string, since I'm not using function so I pass my solution in viewDidLoad
let adzan = "4:01"
let content = UNMutableNotificationContent()
content.title = "Adzan"
content.body = "It's time for sholat"
content.sound = UNNotificationSound.default
// Format the date first from string time
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
//addingTimeInterval is where you want to set notification before or after deciding time in this case I set it 10 minute before deciding time
guard let date = dateFormatter.date(from: adzan)?.addingTimeInterval(-600) else { return }
// and convert our date into dateComponents
let triggerDate = Calendar.current.dateComponents([.hour, .minute, .second], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)

Get sleep hours using HealthKit

I am trying to get sleep hours through HealthKit for particular date.

I have google it but did’t find any specific solution.

 I have also tried to use below code but it did’t work well.

func getSleepHours() {
if let sleepType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.sleepAnalysis) {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd HH:mm"
let startDate = formatter.date(from: "2017/12/02 22:00")
let endDate = formatter.date(from: "2017/12/03 07:31")
// let startDate = Date().yesterday
// let endDate = Date()
//let starTDate = Date)
let predciate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictEndDate)
// let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, startDate: endDate, options: .None)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
let query = HKSampleQuery(sampleType: sleepType, predicate: predciate, limit: 30, sortDescriptors: [sortDescriptor]) { (query, tmpResult, error) -> Void in
if let result = tmpResult {
for item in result {
if let sample = item as? HKCategorySample {
let value = (sample.value == HKCategoryValueSleepAnalysis.inBed.rawValue) ? "InBed" : "Asleep"
print("sleep: \(sample.startDate) \(sample.endDate) - source: \(sample.source.name) - value: \(value)")
// let seconds = endDate.timeIntervalSinceDate(sample.startDate)
let seconds = sample.startDate.timeIntervalSince(sample.endDate)
let minutes = seconds/60
let hours = minutes/60
print(seconds)
print(minutes)
print(hours)
}
}
}else{
print(error?.localizedDescription)
}
}
healthStore.execute(query)
}
}

Notification Not Fire On specificTime

I am trying to send a local notification. My Code is Below mentioned.
Problem Is that notification not fire. i tried all possible answered on stackoverflow. please suggest.
I clear all Notification on did finish launching and also set a user permission for the notification
func applicationWillTerminate(_ application: UIApplication) {
self.loadData()
for obj in eventArray
{
if (obj["notification"] as? Bool)!
{
scheduleNotification(obj["time"] as! Date, obj["title"] as! String)
print(obj["time"] as! Date)
}
}
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func scheduleNotification(_ date: Date, _ title:String) {
let formatter = DateFormatter()
formatter.dateFormat = "HH"
let myhour = formatter.string(from: date)
let number = NumberFormatter()
let mynumberhour = number.number(from: myhour)
let intHour = mynumberhour?.intValue
print(intHour!)
formatter.dateFormat = "mm"
let myminute = formatter.string(from: date)
let mynumberMinute = number.number(from: myminute)
let intMinute = mynumberMinute?.intValue
print(intMinute!)
formatter.dateFormat = "MM"
let mymonth = formatter.string(from: date)
let mynumberMonth = number.number(from: mymonth)
let intMonth = mynumberMonth?.intValue
print(intMonth!)
formatter.dateFormat = "dd"
let myday = formatter.string(from: date)
let mynumberday = number.number(from: myday)
let intday = mynumberday?.intValue
print(intday!)
let calendar = Calendar.current
//let components = calendar.dateComponents(in: .current, from: date)
let newComponents = DateComponents(calendar: calendar, timeZone: .current, month: intMonth, day: intday, hour: intHour, minute: intMinute)
let trigger = UNCalendarNotificationTrigger(dateMatching: newComponents, repeats: true)
let content = UNMutableNotificationContent()
content.title = " Today's Event"
content.body = "Event Is Generated"
content.sound = UNNotificationSound.default()
let request = UNNotificationRequest(identifier: title, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}
}
}
Problem I solved.
I called a "func scheduleNotification" in "func applicationDidEnterBackground" and notification fire properly.

App crashes when calling HKHealthStore's execute method on HKStatisticsCollectionQuery

I'm trying to retrieve the steps data from Health Kit and get an update everytime this data changes.
But when the HKHealthStore calls its execute method on the query, the app crash:
And I have no idea why. Any help is welcome.
Here is my code:
func sretrieveRealTimeSteps(completion: #escaping (Int) -> Void) {
let calendar = Calendar.current
var interval = DateComponents()
interval.day = 1
var anchorComponents = calendar.dateComponents([.day, .month, .year, .weekday], from: Date())
anchorComponents.hour = 0
guard let anchorDate = calendar.date(from: anchorComponents) else { completion(0); return }
guard let quantityType = HKObjectType.quantityType(forIdentifier: .stepCount) else { completion(0); return }
let realTimeQuery = HKStatisticsCollectionQuery(quantityType: quantityType,
quantitySamplePredicate: nil,
options: .cumulativeSum,
anchorDate: anchorDate,
intervalComponents: interval)
realTimeQuery.statisticsUpdateHandler = { query, statistics, results, error in
guard let statsCollection = results else {
completion(0)
return
}
statsCollection.enumerateStatistics(from: Date(), to: Date()) { statistics, stop in
if let quantity = statistics.sumQuantity() {
let value = quantity.doubleValue(for: HKUnit.count())
completion(Int(value))
} else {
completion(0)
}
}
}
healthKitStore.execute(realTimeQuery)
}
Also, when I used a one time query there is no problem:
query.initialResultsHandler = { query, results, error in
guard let statsCollection = results else {
NotificationView.showHealthKitRetrieveInfoFailedNotification()
completion(nil, error)
return
}
var values = [Int]()
let endDate = Date()
let startDate = calendar.date(byAdding: .day, value: -6, to: endDate) ?? Date()
statsCollection.enumerateStatistics(from: startDate, to: endDate) { statistics, stop in
if let quantity = statistics.sumQuantity() {
let date = statistics.startDate
let value = quantity.doubleValue(for: HKUnit.count())
values.append(Int(value))
if date.isSameDayThan(endDate, timeZone: TimeZone.current) {
completion(values, nil)
}
} else {
values.append(0)
if values.count == 7 {
stop.pointee = true
completion(values, nil)
}
}
}
}
EDIT: Stacktrace

EKEvent created and removed if endDate changed

The following code works, no problem at all.
let eventStore = EKEventStore()
eventStore.requestAccessToEntityType(.Event, completion: { (granted, error) in
if granted == false { return }
let e = EKEvent(eventStore: eventStore)
e.title = self.event!.title
let meh = self.event!.commencement
print("\(meh)")
e.startDate = meh
e.location = self.event!.venue.contact.address.assembleAddress()
let bleh = NSDate(timeInterval: Double(60*24*60*60), sinceDate: self.event!.commencement)
print("\(bleh)")
e.endDate = bleh
e.calendar = eventStore.defaultCalendarForNewEvents
e.URL = self.event!.marketingURL
e.addAlarm(EKAlarm(absoluteDate: self.event!.commencement.dateByAddingTimeInterval(Double(-60*60*24*7))))
do {
try eventStore.saveEvent(e, span: .ThisEvent, commit: true)
} catch let error as NSError {
print("error \(error)")
}
})
When I change the end date to 8 hours ahead of the commence date, the event is not created, or for a fleeting moment it is there, then the network activity indicator spins and it is removed.
let eventStore = EKEventStore()
eventStore.requestAccessToEntityType(.Event, completion: { (granted, error) in
if granted == false { return }
let e = EKEvent(eventStore: eventStore)
e.title = self.event!.title
let meh = self.event!.commencement
print("\(meh)")
e.startDate = meh
e.location = self.event!.venue.contact.address.assembleAddress()
let bleh = NSDate(timeInterval: Double(8*60*60), sinceDate: self.event!.commencement)
print("\(bleh)")
e.endDate = bleh
e.calendar = eventStore.defaultCalendarForNewEvents
e.URL = self.event!.marketingURL
e.addAlarm(EKAlarm(absoluteDate: self.event!.commencement.dateByAddingTimeInterval(Double(-60*60*24*7))))
do {
try eventStore.saveEvent(e, span: .ThisEvent, commit: true)
} catch let error as NSError {
print("error \(error)")
}
})
No error is printed. What's going on ?
The date is in the past. Make sure the date is in the future.

Resources