A Helpful Extension to NSDate

2016-01-27

In a recent iOS project written in Swift, I have frequently needed to add various intervals to NSDate objects. Adding some number of seconds to an NSDate is simple:

// Jan 1, 1970, 0:00 AM
let epoch = NSDate(timeIntervalSince1970: 0)

// Jan 1, 1970, 0:01 AM
epoch.dateByAddingTimeInterval(60)

If we start with an NSDate initialized to the epoch, we call the dateByAddingTimeInterval instance method with some number of seconds. If we want to instead add some number of days, any caller of the method has to calculate the number of seconds in a day.

let secondsInADay: NSTimeInterval = 60 * 60 * 24

// Jan 2, 1970, 0:00 AM
epoch.dateByAddingTimeInterval(secondsInADay)

Calculating the number of seconds in a day is simple, but it puts an unnecessary demand on the callers of the function. The demand becomes even more onerous when a caller wants to add multiple days to a date. Instead, let's add an extension to NSDate to make the interface simpler.

extension NSDate {
    func adding(days days: Int) -> NSDate {
        let secondsInAMinute = 60
        let secondsInAnHour = 60 * secondsInAMinute
        let secondsInADay = 24 * secondsInAnHour

        return self.dateByAddingTimeInterval(
            NSTimeInterval(days * secondsInADay)
        )
    }
}

Now with our extension in place, we can add a day to any NSDate as follows:

// Jan 2, 1970, 0:00 AM
epoch.adding(days: 1)

From here, it's fairly easy imagining how to improve our adding function to include not just days, but also hours, minutes, seconds:

extension NSDate {
    func adding(days days: Int = 0, hours: Int = 0, minutes: Int = 0, seconds: Int = 0) -> NSDate {
        let secondsInAMinute = 60
        let secondsInAnHour = 60 * secondsInAMinute
        let secondsInADay = 24 * secondsInAnHour

        return self.dateByAddingTimeInterval(
            NSTimeInterval(days * secondsInADay) +
                NSTimeInterval(hours * secondsInAnHour) +
                NSTimeInterval(minutes * secondsInAMinute) +
                NSTimeInterval(seconds)
        )
    }
}

Aside from the additional arguments, the one key difference with the code above is the addition of default values for the arguments. By having defaults, a caller can choose which intervals to pass into the function.