I have a UILocalNotification object that I have setup with repeat intervals day, week, and month. I am having no troubles at all accessing the fire date of the object:
i would just add the repeatInterval until the date lies in the future:
-(NSDate*)nextFireDateForNotification:(UILocalNotification*)notification {
NSCalendar *calendar = notification.repeatCalendar;
if (!calendar) {
calendar = [NSCalendar currentCalendar];
}
NSDate* date = [notification.fireDate copy];
while (date.timeIntervalSinceNow > 0) {
date = [calendar dateByAddingUnit:notification.repeatInterval value:1 toDate:date options:0];
}
return date;
}
This is in Swift 4 and using calendar's nextDate
func.
extension UILocalNotification {
var nextFireDate: Date? {
guard let fireDate = fireDate else { return nil }
let today = Date()
let cal = Calendar.current
if fireDate.compare(today) == .orderedDescending {
return fireDate
}
let s: Set<Calendar.Component>
switch repeatInterval {
case .year: s = [.month, .day, .hour, .minute, .second]
case .month: s = [.day, .hour, .minute, .second]
case .day: s = [.hour, .minute, .second]
case .hour: s = [.minute, .second]
case .minute: s = [.second]
default: return nil // Not supporting other intervals
}
let components = cal.dateComponents(s, from: fireDate)
return cal.nextDate(after: today, matching: components, matchingPolicy: .nextTimePreservingSmallerComponents)
}
}
I don't think the next fire date is available as a property but rather calculated from fireDate
and repeatInterval
. Date calculating can be tricky with different time zones and other nasty things. In your example you have chosen a daily repeat and to calculate the next fire date you can do something along the lines of:
NSCalendar *calendar = localNotif.repeatCalendar;
if (!calendar) {
calendar = [NSCalendar currentCalendar];
}
NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease];
components.day = 1;
NSDate *nextFireDate = [calendar dateByAddingComponents:components toDate:localnotif.fireDate options:0];
If you use some other repeat interval you would have to change the code accordingly. If you were to use NSMonthCalendarUnit
you would have to use components.month = 1
instead.
To calculate the next fire date for a repeating UILocalNotification
, you have to:
repeatInterval
there's been between the notification's original fire date (i.e. its fireDate
property) and now.fireDate
.Here's one approach:
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDateComponents *difference = [calendar components:notif.repeatInterval
fromDate:notif.fireDate
toDate:[NSDate date]
options:0];
NSDate *nextFireDate = [calendar dateByAddingComponents:difference
toDate:notif.fireDate
options:0];
This works in many scenarios, but here's a scenario where it won't work:
Suppose that:
repeatInterval
is NSDayCalendaryUnit
(i.e. repeat daily)The above code will calculate the difference to 7 days (01/01 + 7 days = 08/01), add them to fireDate
, and thus set nextFireDate
to 08/01 at 2pm. But that's in the past, we want nextFireDate
to be 09/01 at 2pm!
So if using the above code and your repeatInterval
is NSDayCalendaryUnit
, then add these lines:
if ([nextFireDate timeIntervalSinceDate:[NSDate date]] < 0) {
//next fire date should be tomorrow!
NSDateComponents *extraDay = [[NSDateComponents alloc] init];
extraDay.day = 1;
nextFireDate = [calendar dateByAddingComponents:extraDay toDate:nextFireDate options:0];
}
I marked this answer as community wiki, feel free to edit it if you have found a better way to do the calculation!