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

uhfocuz picture uhfocuz · Nov 28, 2014 · Viewed 112.2k times · Source

I am trying to get the difference between the current date as NSDate() and a date from a PHP time(); call for example: NSDate(timeIntervalSinceReferenceDate: 1417147270). How do I go about getting the difference in time between the two dates. 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.

How should I go about this?

EDIT: The current accepted answer has done exactly what I've wanted to do. I recommend it for easy usage for getting the time between two dates in the form that that PHP time() function uses. If you aren't particularly familiar with PHP, that's the time in seconds from January 1st, 1970. This is beneficial for a backend in PHP. If perhaps you're using a backend like NodeJS you might want to consider some of the other options you'll find below.

Answer

Leo Dabus picture Leo Dabus · Nov 28, 2014

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, .second]
dateComponentsFormatter.maximumUnitCount = 1
dateComponentsFormatter.unitsStyle = .full
dateComponentsFormatter.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)     // 0
let months = date2.months(from: date1)   // 9
let weeks = date2.weeks(from: date1)     // 39
let days = date2.days(from: date1)       // 273
let hours = date2.hours(from: date1)     // 6,553
let minutes = date2.minutes(from: date1) // 393,180
let seconds = date2.seconds(from: date1) // 23,590,800

let 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"