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
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?
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.
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.
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
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.