Repeat Push Notification Every X Hours On The Hour - ios

With UNCalendarNotificationTrigger I can get it to repeat at a specific hour every day.
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
With UNTimeIntervalNotificationTrigger I can get it to repeat by some interval from when the timer was created.
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: Double(frequency*60), repeats: true)
How though, can I get a push notification to repeat on the hour, at some flexible interval? For example, from 12:00am, every 2 hours, every 3 hours, or every 12 hours, and so on.

Well, if you know you can set a specific time to repeat at each day, why not calculate the times based on the interval yourself?
var components = DateComponents()
components.hour = 5
components.second = 0
let interval: Double = 60 * 30 // 30 min
let maxDuration: Double = 60 * 60 * 5 // 5 hours
let startDate = Calendar.current.date(
byAdding: components,
to: Calendar.current.startOfDay(for: Date()))
let endDate = startDate.addingTimeInterval(maxDuration)
let notificationCount: Int = Int((endDate.timeIntervalSince1970 - startDate.timeIntervalSince1970) / maxDuration)
(0..<notificationCount)
.map({ startDate.addingTimeInterval(Double($0) * interval) })
.forEach({ date in
// Schedule notification for each date here
})
You're going to have to manage the ranges and the day overlap yourself, but this should point you in the right direction.

Related

DateComponentsFormatter drop zero hours but not zero minutes

I'm trying to use a DateComponentsFormatter to format a number of seconds into a time string HH:MM:SS. I always want to show the minutes and seconds fields but I don't want to show hours if hours is 0. I tried setting
formatter.zeroFormattingBehavior = .dropLeading
But, this causes the minutes to be dropped as well if both hours and minutes are 0.
Currently, my solution is as follows:
if timeElapsed >= 3600 {
formatter.allowedUnits = [.second, .minute, .hour]
} else {
formatter.allowedUnits = [.second, .minute]
}
formatter.zeroFormattingBehavior = .pad
However, I'm concerned that this solution is very hacky and won't work correctly if there is some internationalization that doesn't consider one hour to be 3600 seconds. Is there a better solution?

DateComponentsFormatter - showing only hour described as minutes - bug?

I'm using DateComponentsFormatter to achieve something like that: "1 hour, 30 min". This is my code for that:
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .short
formatter.allowedUnits = [.hour, .minute]
return formatter.string(from: 90)!
This should return 1 hour and 30 minutes but my output is "1 min". Is something wrong with my code or is it iOS bug?
The DataComponentsFormatter string(from: TimeInterval) method that you are using expects the time interval in seconds.
So you are asking the formatter to format 90 seconds, not 90 minutes.
This will solve your issue:
return formatter.string(from: 90 * 60)! // 90 minutes
When ever in doubt about such things, read the documentation. The documentation shows the following for the parameter description:
The time interval, measured in seconds. The value must be a finite number. Negative numbers are treated as positive numbers when creating the string.

Convert NSTimeInterval to hours in decimals

I'm working on an app, in which I take the difference between 2 NSdates, and get the interval in between using NSTimeInterval
let timediff = timeDownValue?.timeIntervalSinceDate(timeUpValue!)
then using my new timeDiff constant, I update my timeTotals var
var totalTime = NSTimeInterval()
Now, what I need to do from there is to convert this NSTimeInterval to a Decimal, because that's what they use to calculate the time. so for example if my interval between date1 and date2 is 30 minutes, I want my final output to be 0.5
I can't seems to figure out how
thanks
Your timediff variable is already a decimal value for the number of seconds. To convert that into hours, divide by 3600.
let timediff = timeDownValue?.timeIntervalSinceDate(timeUpValue!)
var totalTime = timediff / 3600.0
Here, totalTime will be in hours.

How to get time interval until date

I would like to get the time interval from the present date and time until a certain date in the future. All I could manage to do is get the interval but with a minus in front of all, because i used this:
let elapsedTime = NSDate().timeIntervalSinceDate(GeneralUtils.dateFromString(endDate))
let formatter = NSDateComponentsFormatter()
formatter.unitsStyle = .Abbreviated
let countdown = formatter.stringFromTimeInterval(elapsedTime)
timerLabel.text! = "\(countdown!)"
How could I fix it to show me the positive interval?
Now it shows me something like this "-1d 3h 23m 10s"
Just use abs() so the time interval is always positive. (Just me being insane)
Of course Russell points out you could just swap the dates around...
let elapsedTime = GeneralUtils.dateFromString(endDate).timeIntervalSinceNow

UIDatePicker Time Issues

I have a problem with my UIDatePicker:
When it first appears on the view as you'll see in the screenshot,
the initial value of the UIDatePicker says Today 3:00 pm, but if I click on the done button the label shows 3:07 ( which is the actual time ).
I want the Label to display the same time as the UIDatePicker.
here is my code:
override func viewDidLoad() {
super.viewDidLoad()
myDatePicker.minuteInterval = 15
}
#IBAction func datePickerAction(sender: AnyObject) {
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm"
var strDate = dateFormatter.stringFromDate(myDatePicker.date)
self.selectedDate.text = strDate
}
You need to adjust the initial date to the discrete minute amounts at first. I am sure your date picker works just fine once you change the value, right? When you set the date picker to a date (like 3:07) but the date picker is set to show only increments of 15 minutes, it will show 3:00, but the set date is still 3:07.
let allUnits = NSCalendarUnit(rawValue: UInt.max)
let components = NSCalendar.currentCalendar().components(allUnits, fromDate: NSDate())
var minute = components.minute
minute = (minute / 15) * 15
components.minute = minute
let datePickerDate = NSCalendar.currentCalendar().dateFromComponents(components)
This always rounds the minutes downwards (while you might want to round up if the minute % 15 > 7 and then account for rounding up to 60), but you get the idea.

Resources