The way I did this in Swift 2.3 was:
let currentDate = NSDate()
let currentCalendar = NSCalendar.currentCalendar()
var startDate : NSDate?
var endDate : NSDate?
// The following two lines set the `startDate` and `endDate` to the start of the day
currentCalendar.rangeOfUnit(.Day, startDate: &startDate, interval: nil, forDate: currentDate)
currentCalendar.rangeOfUnit(.Day, startDate: &endDate, interval: nil, forDate: self)
let intervalComps = currentCalendar.components([.Day], fromDate: startDate!, toDate: endDate!, options: [])
print(intervalComps.day)
Now this has all changed with Swift 3. I have to either use NSCalendar
and NSDate
by constantly type casting with as
, or find the Swift 3 way of doing it.
What's the right way to do it in Swift 3?
Turns out this is much simpler to do in Swift 3:
extension Date {
func interval(ofComponent comp: Calendar.Component, fromDate date: Date) -> Int {
let currentCalendar = Calendar.current
guard let start = currentCalendar.ordinality(of: comp, in: .era, for: date) else { return 0 }
guard let end = currentCalendar.ordinality(of: comp, in: .era, for: self) else { return 0 }
return end - start
}
}
Edit
Comparing the ordinality of the two dates should be within the same era
instead of the same year
, since naturally the two dates may fall in different years.
Usage
let yesterday = Date(timeInterval: -86400, since: Date())
let tomorrow = Date(timeInterval: 86400, since: Date())
let diff = tomorrow.interval(ofComponent: .day, fromDate: yesterday)
// return 2