简体   繁体   中英

How to grab the NEXT fire date from a UILocalNotification object

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:

[cell.detailTextLabel setText:[notification1.fireDate description]];

But I am having troubles getting the next fire date. If I print out the above notification1 object to the console, I get this:

<UIConcreteLocalNotification: 0x613e060>{fire date = 2010-11-29 03:53:52 GMT, time zone = America/Denver (MST) offset -25200, repeat interval = 16, next fire date = 2010-11-30 03:53:52 GMT}

This object contains somewhere the value or data I need to display the next fire date...but I can't find it! Does anybody know where I can get it programmatically?

Thanks

To calculate the next fire date for a repeating UILocalNotification , you have to:

  1. Figure out the amount of repeatInterval there's been between the notification's original fire date (ie its fireDate property) and now.
  2. Add them to the notification's 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:

  • the notification's `fireDate is 01/01 at 2:00pm
  • the notification's repeatInterval is NSDayCalendaryUnit (ie repeat daily)
  • The date now is 08/01 at 3:00pm

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!

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.

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)
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM