以(月/日/小时/分钟/秒)计算两个NSDates之间的差异

我试图得到作为NSDate()的当前日期和来自PHP time();的日期之间的区别time(); 调用例如: NSDate(timeIntervalSinceReferenceDate: 1417147270) 。 我如何才能在这两个日期之间获得时间上的差异。 我想有一个函数比较两个日期, if(seconds > 60)那么它返回分钟, if(minutes > 60)返回小时, if(hours > 24)返回几天等等。

我应该怎么做呢?

编辑:目前接受的答案已经完成了我想要做的。 我推荐使用这个函数,以便以PHP time()函数使用的格式获取两个日期之间的time() 。 如果您对PHP不是特别熟悉的话,那么从1970年1月1日起,这个时间只需几秒钟。这对PHP中的后端是有利的。 如果你使用的是像NodeJS这样的后端,你可能需要考虑下面的其他一些选项。

Xcode 8.3•Swift 3.1

您可以使用日历帮助您创建一个扩展名,以按照以下方式进行日期计算:

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

使用日期组件格式化程序

 let dateComponentsFormatter = DateComponentsFormatter() dateComponentsFormatter.allowedUnits = [.year,.month,.weekOfYear,.day,.hour,.minute,.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" 

如果有人需要显示所有的时间单位,例如“小时分秒”,而不是“小时”。 假设两个日期之间的时间差是1小时59分20秒。 此功能将显示“1小时59分20秒”。

这是我的代码:

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

在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 "" } } 

你问:

我想有一个函数比较两个日期,如果(秒> 60),那么它返回分钟,如果(分钟> 60)返回小时,如果(小时> 24)返回几天等等。

我假设你正在试图建立两个日期之间的经过时间的字符串表示。 苹果公司已经有了一个专门设计来完成这个功能的课程,而不是编写自己的代码。 也就是说,使用DateComponentsFormatter ,将allowedUnits设置为对您的应用程序有意义的任何值,将unitsStyle设置为任何您想要的(例如.full ),然后调用string(from:to:)

例如在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) 

这也将本地化适合于该设备的字符串。

或者,在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) 

如果您正在查找实际的数值,只需使用dateComponents 。 例如在Swift 3:

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

或者,在Swift 2.3中:

 let components = NSCalendar.currentCalendar().components([.Month, .Day, .Hour, .Minute, .Second], fromDate: previousDate, toDate: now, options: []) 
  func dateDiff(dateStr:String) -> String { var f:NSDateFormatter = NSDateFormatter() f.timeZone = NSTimeZone.localTimeZone() f.dateFormat = "yyyy-M-dd'T'HH:mm:ss.SSSZZZ" var now = f.stringFromDate(NSDate()) var startDate = f.dateFromString(dateStr) var endDate = f.dateFromString(now) var calendar: NSCalendar = NSCalendar.currentCalendar() let calendarUnits = NSCalendarUnit.CalendarUnitWeekOfMonth | NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitHour | NSCalendarUnit.CalendarUnitMinute | NSCalendarUnit.CalendarUnitSecond let dateComponents = calendar.components(calendarUnits, fromDate: startDate!, toDate: endDate!, options: nil) let weeks = abs(dateComponents.weekOfMonth) let days = abs(dateComponents.day) let hours = abs(dateComponents.hour) let min = abs(dateComponents.minute) let sec = abs(dateComponents.second) var timeAgo = "" if (sec > 0){ if (sec > 1) { timeAgo = "\(sec) Seconds Ago" } else { timeAgo = "\(sec) Second Ago" } } if (min > 0){ if (min > 1) { timeAgo = "\(min) Minutes Ago" } else { timeAgo = "\(min) Minute Ago" } } if(hours > 0){ if (hours > 1) { timeAgo = "\(hours) Hours Ago" } else { timeAgo = "\(hours) Hour Ago" } } if (days > 0) { if (days > 1) { timeAgo = "\(days) Days Ago" } else { timeAgo = "\(days) Day Ago" } } if(weeks > 0){ if (weeks > 1) { timeAgo = "\(weeks) Weeks Ago" } else { timeAgo = "\(weeks) Week Ago" } } print("timeAgo is===> \(timeAgo)") return timeAgo; } 

我给Leo Dabus添加了一个“长”的版本,以防你想要一个字符串像“2周前”,而不是“2w”。

 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([.weekOfYear], from: date, to: self).weekOfYear ?? 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 "" } func offsetLong(from date: Date) -> String { if years(from: date) > 0 { return years(from: date) > 1 ? "\(years(from: date)) years ago" : "\(years(from: date)) year ago" } if months(from: date) > 0 { return months(from: date) > 1 ? "\(months(from: date)) months ago" : "\(months(from: date)) month ago" } if weeks(from: date) > 0 { return weeks(from: date) > 1 ? "\(weeks(from: date)) weeks ago" : "\(weeks(from: date)) week ago" } if days(from: date) > 0 { return days(from: date) > 1 ? "\(days(from: date)) days ago" : "\(days(from: date)) day ago" } if hours(from: date) > 0 { return hours(from: date) > 1 ? "\(hours(from: date)) hours ago" : "\(hours(from: date)) hour ago" } if minutes(from: date) > 0 { return minutes(from: date) > 1 ? "\(minutes(from: date)) minutes ago" : "\(minutes(from: date)) minute ago" } if seconds(from: date) > 0 { return seconds(from: date) > 1 ? "\(seconds(from: date)) seconds ago" : "\(seconds(from: date)) second ago" } return "" } } 

Swift 3.0稍微修改的代码

 let calendar = NSCalendar.current as NSCalendar // Replace the hour (time) of both dates with 00:00 let date1 = calendar.startOfDay(for: startDateTime) let date2 = calendar.startOfDay(for: endDateTime) let flags = NSCalendar.Unit.day let components = calendar.components(flags, from: date1, to: date2, options: []) return components.day! 

随着Swift 3,根据您的需求,您可以选择以下两种方式之一来解决您的问题。


1.向用户显示两个日期之间的差异

您可以使用DateComponentsFormatter为您的应用程序界面创建字符串。 DateComponentsFormatter具有maximumUnitCount属性,并具有以下声明:

 var maximumUnitCount: Int { get set } 

使用此属性来限制结果字符串中显示的单位数。 例如,将此属性设置为2,而不是“1h 10m,30s”,结果字符串将为“1h 10m”。 限制空间时使用此属性或想要将值四舍五入到最近的大单位。

通过设置maximumUnitCount的值为1 ,可以保证只显示一个DateComponentsFormatter的单位(年,月,日,小时或分钟)的差异。

下面的Playground代码显示了如何显示两个日期之间的差异:

 import Foundation let oldDate = Date(timeIntervalSinceReferenceDate: -16200) let newDate = Date(timeIntervalSinceReferenceDate: 0) let dateComponentsFormatter = DateComponentsFormatter() dateComponentsFormatter.allowedUnits = [NSCalendar.Unit.year, .month, .day, .hour, .minute] dateComponentsFormatter.maximumUnitCount = 1 dateComponentsFormatter.unitsStyle = DateComponentsFormatter.UnitsStyle.full let timeDifference = dateComponentsFormatter.string(from: oldDate, to: newDate) print(String(reflecting: timeDifference)) // prints Optional("5 hours") 

请注意DateComponentsFormatter四舍五入结果。 因此, 4小时30分钟的差别将显示为5小时

如果你需要重复这个操作,你可以重构你的代码:

 import Foundation struct Formatters { static let dateComponentsFormatter: DateComponentsFormatter = { let dateComponentsFormatter = DateComponentsFormatter() dateComponentsFormatter.allowedUnits = [NSCalendar.Unit.year, .month, .day, .hour, .minute] dateComponentsFormatter.maximumUnitCount = 1 dateComponentsFormatter.unitsStyle = DateComponentsFormatter.UnitsStyle.full return dateComponentsFormatter }() } extension Date { func offset(from: Date) -> String? { return Formatters.dateComponentsFormatter.string(from: oldDate, to: self) } } let oldDate = Date(timeIntervalSinceReferenceDate: -16200) let newDate = Date(timeIntervalSinceReferenceDate: 0) let timeDifference = newDate.offset(from: oldDate) print(String(reflecting: timeDifference)) // prints Optional("5 hours") 

2.获取两个日期之间的差异,而不格式化

如果您不需要格式化两个日期之间的差异,则可以使用“ CalendarCalendar有一个方法dateComponents(_:from:to:) ,它具有以下声明:

 func dateComponents(_ components: Set<Calendar.Component>, from start: Date, to end: Date) -> DateComponents 

返回两个日期之间的差异。

下面使用dateComponents(_:from:to:)的Playground代码显示了如何通过仅返回一种Calendar.Component (年,月,日,小时或分钟)类型的差异来检索两个日期之间的差异。

 import Foundation let oldDate = Date(timeIntervalSinceReferenceDate: -16200) let newDate = Date(timeIntervalSinceReferenceDate: 0) let descendingOrderedComponents = [Calendar.Component.year, .month, .day, .hour, .minute] let dateComponents = Calendar.current.dateComponents(Set(descendingOrderedComponents), from: oldDate, to: newDate) let arrayOfTuples = descendingOrderedComponents.map { ($0, dateComponents.value(for: $0)) } for (component, value) in arrayOfTuples { if let value = value, value > 0 { print(component, value) // prints hour 4 break } } 

如果你需要重复这个操作,你可以重构你的代码:

 import Foundation extension Date { func offset(from: Date) -> (Calendar.Component, Int)? { let descendingOrderedComponents = [Calendar.Component.year, .month, .day, .hour, .minute] let dateComponents = Calendar.current.dateComponents(Set(descendingOrderedComponents), from: from, to: self) let arrayOfTuples = descendingOrderedComponents.map { ($0, dateComponents.value(for: $0)) } for (component, value) in arrayOfTuples { if let value = value, value > 0 { return (component, value) } } return nil } } let oldDate = Date(timeIntervalSinceReferenceDate: -16200) let newDate = Date(timeIntervalSinceReferenceDate: 0) if let (component, value) = newDate.offset(from: oldDate) { print(component, value) // prints hour 4 } 

在Swift 2.2中

  /// Returns the amount of years from another date func years(fromdate: NSDate) -> Int { return NSCalendar.currentCalendar().components([.Year], fromDate: fromdate, toDate: NSDate(), options: []).year ?? 0 } /// Returns the amount of months from another date func months(fromdate: NSDate) -> Int { return NSCalendar.currentCalendar().components([.Month], fromDate: fromdate, toDate: NSDate(), options: []).month ?? 0 } /// Returns the amount of weeks from another date func weeks(fromdate: NSDate) -> Int { return NSCalendar.currentCalendar().components([.WeekOfYear], fromDate: fromdate, toDate: NSDate(), options: []).weekOfYear ?? 0 } /// Returns the amount of days from another date func days(fromdate: NSDate) -> Int { return NSCalendar.currentCalendar().components([.Day], fromDate: fromdate, toDate: NSDate(), options: []).day ?? 0 } /// Returns the amount of hours from another date func hours(fromdate: NSDate) -> Int { return NSCalendar.currentCalendar().components([.Hour], fromDate: fromdate, toDate: NSDate(), options: []).hour ?? 0 } /// Returns the amount of minutes from another date func minutes(fromdate: NSDate) -> Int { return NSCalendar.currentCalendar().components([.Minute], fromDate: fromdate, toDate: NSDate(), options: []).minute ?? 0 } /// Returns the amount of seconds from another date func seconds(fromdate: NSDate) -> Int { return NSCalendar.currentCalendar().components(.Second, fromDate: fromdate, toDate: NSDate(), options: []).second ?? 0 } 

从@ leo-dabus的答案合并Extension + DateComponentsFormatter

Xcode 8.3•Swift 3.1

 extension DateComponentsFormatter { func difference(from fromDate: Date, to toDate: Date) -> String? { self.allowedUnits = [.year,.month,.weekOfMonth,.day] self.maximumUnitCount = 1 self.unitsStyle = .full return self.string(from: fromDate, to: toDate) } } let dateComponentsFormatter = DateComponentsFormatter() dateComponentsFormatter.difference(from: Date(), to: Date(timeIntervalSinceNow: 4000000)) // "1 month" 

如果您的目的是要获得两个日期之间的确切日期编号,您可以像这样解决这个问题:

 // Assuming that firstDate and secondDate are defined // ... var calendar: NSCalendar = NSCalendar.currentCalendar() // Replace the hour (time) of both dates with 00:00 let date1 = calendar.startOfDayForDate(firstDate) let date2 = calendar.startOfDayForDate(secondDate) let flags = NSCalendarUnit.DayCalendarUnit let components = calendar.components(flags, fromDate: date1, toDate: date2, options: nil) components.day // This will return the number of day(s) between dates 

这是更短的版本:基本上,我试图得到现在与Date()的发布时间戳之间的差异。

 // MARK: - UPDATE Time Stamp static func updateTimeStampPost(postTimeStamp: Date?, _ completion: (_ finalString: String?) -> Void) { // date in the current state let date = Date() let dateComponentFormatter = DateComponentsFormatter() // change the styling date, wether second minute or hour dateComponentFormatter.unitsStyle = .abbreviated dateComponentFormatter.allowedUnits = [.second, .minute, .hour, .day, .weekOfMonth] dateComponentFormatter.maximumUnitCount = 1 // return the date new format as a string in the completion completion(dateComponentFormatter.string(from: postTimeStamp!, to: date)) } 

这是我对上面的Swift 3答案的回答。 这是截至2016年11月的最新版本,Xcode版本是8.2 Beta(8C23)。 上面使用了Sagar和Emin的一些建议,有时不得不让Xcode自动完成来提示语法。 这个语法看起来真的变成了这个测试版本。 buyDate我从DatePicker获得:

 let calendar = NSCalendar.current as NSCalendar let currentDate = Date() let date1 = calendar.startOfDay(for: buyDate!) let date2 = calendar.startOfDay(for: currentDate) let flags = NSCalendar.Unit.day let components = calendar.components(flags, from: date1, to: date2) NSLog(" day= \(components.day)") 

对于XCode版本8.3.3和Swift 3.0:

  let dateFormatter = DateFormatter() dateFormatter.dateStyle = .medium dateFormatter.timeStyle = .short var beginDate = "2017-08-24 12:00:00" var endDate = "2017-09-07 12:00:00" let startDateTime = dateFormatter.date(from: beginDate) //according to date format your date string print(startDateTime ?? "") //Convert String to Date let endDateTime = dateFormatter.date(from: endDate) //according to date format your date string print(endDateTime ?? "") //Convert String to Date let dateComponentsFormatter = DateComponentsFormatter() dateComponentsFormatter.allowedUnits = [NSCalendar.Unit.minute,NSCalendar.Unit.hour,NSCalendar.Unit.day] let interval = endDateTime!.timeIntervalSince(startDateTime!) var diff = dateComponentsFormatter.string(from: interval)! print(diff) var day_i = 0 var hour_i = 0 var min_i = 0 if (diff.contains("d")) { let day = diff.substring(to: (diff.range(of: "d")?.lowerBound)!) day_i = Int(day)! print ("day --> \(day_i)") diff = diff.substring(from:(diff.range(of : " ")?.upperBound )!) print(diff) } let hour = diff.substring(to: (diff.range(of : ":")?.lowerBound )!) hour_i = Int(hour)! print ("hour --> \(hour_i)") let min = diff.substring(from: (diff.range(of : ":")?.upperBound )!) min_i = Int(min)! print ("min --> \(min_i)") 

Leo Dabus提供复数版本的答案的一小部分,并且更易于人类阅读。

Swift 3

 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) == 1 { return "\(years(from: date)) year" } else if years(from: date) > 1 { return "\(years(from: date)) years" } if months(from: date) == 1 { return "\(months(from: date)) month" } else if months(from: date) > 1 { return "\(months(from: date)) month" } if weeks(from: date) == 1 { return "\(weeks(from: date)) week" } else if weeks(from: date) > 1 { return "\(weeks(from: date)) weeks" } if days(from: date) == 1 { return "\(days(from: date)) day" } else if days(from: date) > 1 { return "\(days(from: date)) days" } if hours(from: date) == 1 { return "\(hours(from: date)) hour" } else if hours(from: date) > 1 { return "\(hours(from: date)) hours" } if minutes(from: date) == 1 { return "\(minutes(from: date)) minute" } else if minutes(from: date) > 1 { return "\(minutes(from: date)) minutes" } return "" } 

}