How to grab the NEXT fire date from a UILocalNotification object

前端 未结 4 750
[愿得一人]
[愿得一人] 2020-12-06 08:13

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:

相关标签:
4条回答
  • 2020-12-06 08:42

    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;
        }
    
    0 讨论(0)
  • 2020-12-06 08:52

    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)
        }
    
    }
    
    0 讨论(0)
  • 2020-12-06 08:54

    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.

    0 讨论(0)
  • 2020-12-06 08:55

    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 (i.e. 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 (i.e. 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!

    0 讨论(0)
提交回复
热议问题