Getting the difference between two Dates (months/days/hours/minutes/seconds) in Swift Getting the difference between two Dates (months/days/hours/minutes/seconds) in Swift ios ios

Getting the difference between two Dates (months/days/hours/minutes/seconds) in Swift


Xcode 8.3 • Swift 3.1 or later

You can use Calendar to help you create an extension to do your date calculations as follow:

extension Date {    /// Returns the amount of years from another date    func years(from date: Date) -> Int {        return Calendar.current.dateComponents([.year], from: date, to: self).year ?? 0    }    /// Returns the amount of months from another date    func months(from date: Date) -> Int {        return Calendar.current.dateComponents([.month], from: date, to: self).month ?? 0    }    /// Returns the amount of weeks from another date    func weeks(from date: Date) -> Int {        return Calendar.current.dateComponents([.weekOfMonth], from: date, to: self).weekOfMonth ?? 0    }    /// Returns the amount of days from another date    func days(from date: Date) -> Int {        return Calendar.current.dateComponents([.day], from: date, to: self).day ?? 0    }    /// Returns the amount of hours from another date    func hours(from date: Date) -> Int {        return Calendar.current.dateComponents([.hour], from: date, to: self).hour ?? 0    }    /// Returns the amount of minutes from another date    func minutes(from date: Date) -> Int {        return Calendar.current.dateComponents([.minute], from: date, to: self).minute ?? 0    }    /// Returns the amount of seconds from another date    func seconds(from date: Date) -> Int {        return Calendar.current.dateComponents([.second], from: date, to: self).second ?? 0    }    /// Returns the a custom time interval description from another date    func offset(from date: Date) -> String {        if years(from: date)   > 0 { return "\(years(from: date))y"   }        if months(from: date)  > 0 { return "\(months(from: date))M"  }        if weeks(from: date)   > 0 { return "\(weeks(from: date))w"   }        if days(from: date)    > 0 { return "\(days(from: date))d"    }        if hours(from: date)   > 0 { return "\(hours(from: date))h"   }        if minutes(from: date) > 0 { return "\(minutes(from: date))m" }        if seconds(from: date) > 0 { return "\(seconds(from: date))s" }        return ""    }}

Using Date Components Formatter

let dateComponentsFormatter = DateComponentsFormatter()dateComponentsFormatter.allowedUnits = [.second, .minute, .hour, .day, .weekOfMonth, .month, .year]dateComponentsFormatter.maximumUnitCount = 1dateComponentsFormatter.unitsStyle = .fulldateComponentsFormatter.string(from: Date(), to: Date(timeIntervalSinceNow: 4000000))  // "1 month"

let date1 = DateComponents(calendar: .current, year: 2014, month: 11, day: 28, hour: 5, minute: 9).date!let date2 = DateComponents(calendar: .current, year: 2015, month: 8, day: 28, hour: 5, minute: 9).date!let years = date2.years(from: date1)     // 0let months = date2.months(from: date1)   // 9let weeks = date2.weeks(from: date1)     // 39let days = date2.days(from: date1)       // 273let hours = date2.hours(from: date1)     // 6,553let minutes = date2.minutes(from: date1) // 393,180let seconds = date2.seconds(from: date1) // 23,590,800let timeOffset = date2.offset(from: date1) // "9M"let date3 = DateComponents(calendar: .current, year: 2014, month: 11, day: 28, hour: 5, minute: 9).date!let date4 = DateComponents(calendar: .current, year: 2015, month: 11, day: 28, hour: 5, minute: 9).date!let timeOffset2 = date4.offset(from: date3) // "1y"let date5 = DateComponents(calendar: .current, year: 2017, month: 4, day: 28).date!let now = Date()let timeOffset3 = now.offset(from: date5) // "1w"


If someone needs to display all time units e.g "hours minutes seconds" not just "hours". Let's say the time difference between two dates is 1hour 59minutes 20seconds. This function will display "1h 59m 20s".

Here is my Objective-C code:

extension NSDate {    func offsetFrom(date: NSDate) -> String {        let dayHourMinuteSecond: NSCalendarUnit = [.Day, .Hour, .Minute, .Second]        let difference = NSCalendar.currentCalendar().components(dayHourMinuteSecond, fromDate: date, toDate: self, options: [])        let seconds = "\(difference.second)s"        let minutes = "\(difference.minute)m" + " " + seconds        let hours = "\(difference.hour)h" + " " + minutes        let days = "\(difference.day)d" + " " + hours        if difference.day    > 0 { return days }        if difference.hour   > 0 { return hours }        if difference.minute > 0 { return minutes }        if difference.second > 0 { return seconds }        return ""    }}

In Swift 3+:

extension Date {    func offsetFrom(date: Date) -> String {        let dayHourMinuteSecond: Set<Calendar.Component> = [.day, .hour, .minute, .second]        let difference = NSCalendar.current.dateComponents(dayHourMinuteSecond, from: date, to: self)        let seconds = "\(difference.second ?? 0)s"        let minutes = "\(difference.minute ?? 0)m" + " " + seconds        let hours = "\(difference.hour ?? 0)h" + " " + minutes        let days = "\(difference.day ?? 0)d" + " " + hours        if let day = difference.day, day          > 0 { return days }        if let hour = difference.hour, hour       > 0 { return hours }        if let minute = difference.minute, minute > 0 { return minutes }        if let second = difference.second, second > 0 { return seconds }        return ""    }}


You ask:

I'd like to have a function that compares the two dates and if(seconds > 60) then it returns minutes, if(minutes > 60) return hours and if(hours > 24) return days and so on.

I'm assuming that you're trying to build a string representation of the elapsed time between two dates. Rather than writing your own code to do that, Apple already has a class designed to do precisely that. Namely, use DateComponentsFormatter, set allowedUnits to whatever values make sense to your app, set unitsStyle to whatever you want (e.g. .full), and then call string(from:to:).

E.g. in Swift 3:

let previousDate = ...let now = Date()let formatter = DateComponentsFormatter()formatter.unitsStyle = .fullformatter.allowedUnits = [.month, .day, .hour, .minute, .second]formatter.maximumUnitCount = 2   // often, you don't care about seconds if the elapsed time is in months, so you'll set max unit to whatever is appropriate in your caselet string = formatter.string(from: previousDate, to: now)

This also will localize the string appropriate for the device in question.

Or, in Swift 2.3:

let previousDate = ...let now = NSDate()let formatter = NSDateComponentsFormatter()formatter.unitsStyle = .Fullformatter.allowedUnits = [.Month, .Day, .Hour, .Minute, .Second]formatter.maximumUnitCount = 2let string = formatter.stringFromDate(previousDate, toDate: now)

If you're looking for the actual numeric values, just use dateComponents. E.g. in Swift 3:

let components = Calendar.current.dateComponents([.month, .day, .hour, .minute, .second], from: previousDate, to: now)

Or, in Swift 2.3:

let components = NSCalendar.currentCalendar().components([.Month, .Day, .Hour, .Minute, .Second], fromDate: previousDate, toDate: now, options: [])