Solución:
Xcode 8.3 • Swift 3.1 o posterior
Puede usar Calendario para ayudarlo a crear una extensión para hacer sus cálculos de fecha de la siguiente manera:
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 ""
}
}
Uso del formateador de componentes de fecha
let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.allowedUnits = [.second, .minute, .hour, .day, .weekOfMonth, .month, .year]
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"
Si alguien necesita mostrar todas las unidades de tiempo, por ejemplo, “horas, minutos, segundos”, no solo “horas”. Digamos que la diferencia de tiempo entre dos fechas es 1 hora 59 minutos 20 segundos. Esta función mostrará “1h 59m 20s”.
Aquí está mi código Objective-C:
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 ""
}
}
En 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 ""
}
}
Usted pregunta:
Me gustaría tener una función que compare las dos fechas y si (segundos> 60) luego devuelve minutos, si (minutos> 60) devuelve horas y si (horas> 24) devuelve días y así sucesivamente.
Supongo que está intentando crear una representación de cadena del tiempo transcurrido entre dos fechas. En lugar de escribir su propio código para hacer eso, Apple ya tiene una clase diseñada para hacer precisamente eso. Es decir, utilice DateComponentsFormatter
, colocar allowedUnits
a los valores que tengan sentido para su aplicación, establezca unitsStyle
a lo que quieras (p. ej. .full
), y luego llame string(from:to:)
.
Por ejemplo, en Swift 3:
let previousDate = ...
let now = Date()
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.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 case
let string = formatter.string(from: previousDate, to: now)
Esto también localizará la cadena apropiada para el dispositivo en cuestión.
O, en Swift 2.3:
let previousDate = ...
let now = NSDate()
let formatter = NSDateComponentsFormatter()
formatter.unitsStyle = .Full
formatter.allowedUnits = [.Month, .Day, .Hour, .Minute, .Second]
formatter.maximumUnitCount = 2
let string = formatter.stringFromDate(previousDate, toDate: now)
Si está buscando los valores numéricos reales, simplemente use dateComponents
. Por ejemplo, en Swift 3:
let components = Calendar.current.dateComponents([.month, .day, .hour, .minute, .second], from: previousDate, to: now)
O, en Swift 2.3:
let components = NSCalendar.currentCalendar().components([.Month, .Day, .Hour, .Minute, .Second], fromDate: previousDate, toDate: now, options: [])