【问题标题】:Getting the difference between two Dates (months/days/hours/minutes/seconds) in Swift在 Swift 中获取两个日期(月/日/小时/分钟/秒)之间的差异
【发布时间】:2022-01-19 22:09:22
【问题描述】:

我正在尝试获取当前日期 NSDate() 与 PHP time(); 调用的日期之间的差异,例如:NSDate(timeIntervalSinceReferenceDate: 1417147270)。如何获取两个日期之间的时间差。我想要一个比较两个日期和if(seconds > 60) 的函数,然后它返回分钟,if(minutes > 60) 返回小时和if(hours > 24) 返回天等等。

我该怎么办?

编辑:当前接受的答案完全符合我的要求。我推荐它以便于使用 PHP time() 函数使用的形式获取两个日期之间的时间。如果您不是特别熟悉 PHP,那是从 1970 年 1 月 1 日开始的秒数。这对 PHP 的后端很有帮助。如果您使用的是 NodeJS 之类的后端,您可能需要考虑以下其他一些选项。

【问题讨论】:

  • 我知道这有点过时了,但你打算如何处理这些差异?例如,如果您希望为用户格式化字符串,您应该使用NSDateComponentsFormatter。它非常可配置,允许您获得适当简洁的结果(例如.maximumUnitCount = 1)。
  • 真的,你打算做什么这个问题是绝对必要的。考虑一个月可以短至 28 天,或多至 31 天加一小时。

标签: ios swift macos date nsdate


【解决方案1】:

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 = [.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"

【讨论】:

  • 在 Swift 2.0 中,.CalendarUnitSecond 报错'NSCalendarUnit.Type' does not have a member named 'CalendarUnitSecond',你知道怎么解决吗?
  • @Matte.Car 你需要使用 .Second 而不是 options: nil 你需要使用 options: []。你可以看看我的编辑。
  • 我讨厌这个答案中的重复,我会使用基于 NSCalendarUnit 的方法,实现为 return Calendar.current().components(unit, from: date, to: self, options: [])?. valueForComponent(unit)(在 iOS > 8 上)。
  • 由于使用DateComponentsFormatter 的答案比长期使用要好得多,所以这确实应该是答案的顶部。
  • 你真是太棒了!这个扩展对我帮助很大!
【解决方案2】:

在 jose920405 答案中添加了一些内容,使其与 Swift 3.0 及更高版本兼容

func getDateTimeDiff(dateStr:String) -> String {
    
    let formatter : DateFormatter = DateFormatter()
    formatter.timeZone = NSTimeZone.local
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    
    let now = formatter.string(from: NSDate() as Date)
    let startDate = formatter.date(from: dateStr)
    let endDate = formatter.date(from: now)
    
    // *** create calendar object ***
    var calendar = NSCalendar.current
    
    // *** Get components using current Local & Timezone ***
    print(calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: startDate!))
    
    // *** define calendar components to use as well Timezone to UTC ***
    let unitFlags = Set<Calendar.Component>([.year, .month, .day, .hour, .minute, .second])
    calendar.timeZone = TimeZone(identifier: "UTC")!
    let dateComponents = calendar.dateComponents(unitFlags, from: startDate!, to: endDate!)
    
    // *** Get Individual components from date ***
    let years = dateComponents.year!
    let months = dateComponents.month!
    let days = dateComponents.day!
    let hours = dateComponents.hour!
    let minutes = dateComponents.minute!
    let seconds = dateComponents.second!
    
    var timeAgo = ""
    
    if (seconds > 0){
        if seconds < 2 {
            timeAgo = "Second Ago"
        }
        else{
            timeAgo = "\(seconds) Second Ago"
        }
    }
    
    if (minutes > 0){
        if minutes < 2 {
            timeAgo = "Minute Ago"
        }
        else{
            timeAgo = "\(minutes) Minutes Ago"
        }
    }
    
    if(hours > 0){
        if hours < 2 {
            timeAgo = "Hour Ago"
        }
        else{
            timeAgo = "\(hours) Hours Ago"
        }
    }
    
    if (days > 0) {
        if days < 2 {
            timeAgo = "Day Ago"
        }
        else{
            timeAgo = "\(days) Days Ago"
        }
    }
    
    if(months > 0){
        if months < 2 {
            timeAgo = "Month Ago"
        }
        else{
            timeAgo = "\(months) Months Ago"
        }
    }
    
    if(years > 0){
        if years < 2 {
            timeAgo = "Year Ago"
        }
        else{
            timeAgo = "\(years) Years Ago"
        }
    }
    
    DLog("timeAgo is ===> \(timeAgo)")
    return timeAgo;
}

【讨论】:

    【解决方案3】:

    Swift 5.1 • iOS 13

    您可以使用 Apple 在 iOS 13 中引入的RelativeDateFormatter

    let exampleDate = Date().addingTimeInterval(-15000)
    
    let formatter = RelativeDateTimeFormatter()
    formatter.unitsStyle = .full
    let relativeDate = formatter.localizedString(for: exampleDate, relativeTo: Date())
    
    print(relativeDate) // 4 hours ago
    

    How to show a relative date and time using RelativeDateTimeFormatter

    【讨论】:

    • 非凡的答案!
    【解决方案4】:

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

    这是我的 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 ""
        }
    
    }
    

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

    【讨论】:

    • 这正是我所需要的。简单,并完成工作。
    • 当差异为 1 天时这不起作用
    • 这帮助我解决了我的问题。谢谢:)
    • 我想得到19天5小时的剩余时间,你能帮忙吗?谢谢
    【解决方案5】:
    import Foundation
    
    extension DateComponents {
    
        func dateComponentsToTimeString() -> String {
    
            var hour = "\(self.hour!)"
            var minute = "\(self.minute!)"
            var second = "\(self.second!)"
    
            if self.hour! < 10 { hour = "0" + hour }
            if self.minute! < 10 { minute = "0" + minute }
            if self.second! < 10 { second = "0" + second }
    
            let str = "\(hour):\(minute):\(second)"
            return str
        }
    
    }
    
    extension Date {
    
        func offset(from date: Date)-> DateComponents {
            let components = Set<Calendar.Component>([.second, .minute, .hour, .day, .month, .year])
            let differenceOfDate = Calendar.current.dateComponents(components, from: date, to: self)
            return differenceOfDate
        }
    }
    

    用途:

    var durationString: String {
            return self.endTime.offset(from: self.startTime).dateComponentsToTimeString()
        }
    

    【讨论】:

      【解决方案6】:

      --> 在 Swift 中使用它来查找两个日期之间的时间间隔(使用两个字符串)。

      func timeGapBetweenDates(previousDate : String,currentDate : String)
      {
          let dateString1 = previousDate
          let dateString2 = currentDate
      
          let Dateformatter = DateFormatter()
          Dateformatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
      
      
          let date1 = Dateformatter.date(from: dateString1)
          let date2 = Dateformatter.date(from: dateString2)
      
      
          let distanceBetweenDates: TimeInterval? = date2?.timeIntervalSince(date1!)
          let secondsInAnHour: Double = 3600
          let minsInAnHour: Double = 60
          let secondsInDays: Double = 86400
          let secondsInWeek: Double = 604800
          let secondsInMonths : Double = 2592000
          let secondsInYears : Double = 31104000
      
          let minBetweenDates = Int((distanceBetweenDates! / minsInAnHour))
          let hoursBetweenDates = Int((distanceBetweenDates! / secondsInAnHour))
          let daysBetweenDates = Int((distanceBetweenDates! / secondsInDays))
          let weekBetweenDates = Int((distanceBetweenDates! / secondsInWeek))
          let monthsbetweenDates = Int((distanceBetweenDates! / secondsInMonths))
          let yearbetweenDates = Int((distanceBetweenDates! / secondsInYears))
          let secbetweenDates = Int(distanceBetweenDates!)
      
      
      
      
          if yearbetweenDates > 0
          {
              print(yearbetweenDates,"years")//0 years
          }
          else if monthsbetweenDates > 0
          {
              print(monthsbetweenDates,"months")//0 months
          }
          else if weekBetweenDates > 0
          {
              print(weekBetweenDates,"weeks")//0 weeks
          }
          else if daysBetweenDates > 0
          {
              print(daysBetweenDates,"days")//5 days
          }
          else if hoursBetweenDates > 0
          {
              print(hoursBetweenDates,"hours")//120 hours
          }
          else if minBetweenDates > 0
          {
              print(minBetweenDates,"minutes")//7200 minutes
          }
          else if secbetweenDates > 0
          {
              print(secbetweenDates,"seconds")//seconds
          }
      }
      

      【讨论】:

        【解决方案7】:

        使用此代码:

        let registrationDateString = "2008-10-06 00:00:00"
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss"
            if let registrationDate = dateFormatter.date(from: registrationDateString) {
                let currentDate = Date()
                let dateDifference = Calendar.current.dateComponents([.day, .month, .year],
                                                                       from: registrationDate,
                                                                       to: currentDate)
                print("--------------------- Result: \(dateDifference.year ?? 0) years \(dateDifference.month ?? 0) months and \(dateDifference.day ?? 0) days")
            } else {
                print("--------------------- No result")
            }
        

        输出为:结果:10 年 1 个月零 18 天

        【讨论】:

          【解决方案8】:

          对 Leo Dabus 的回答做了一个小补充,以提供复数版本并更易于阅读。

          斯威夫特 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 ""
              }
          }
          

          【讨论】:

            【解决方案9】:

            对于 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)")
            

            【讨论】:

              【解决方案10】:

              这是我对上述 Swift 3 答案的回答。这是截至 2016 年 11 月的最新版本,Xcode 版本是 8.2 Beta (8C23)。使用了上面的一些 Sagar 和 Emin 建议,有时不得不让 Xcode 自动完成来建议语法。看起来语法真的变成了这个 beta 版本。 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)")
              

              【讨论】:

              • 对不起,现在我看到了这个,这是 Sagar 的解决方案。我做了很多次迭代,尝试了很多我认为已经改变的事情。 Emin 的解决方案不适用于最新的 Swift 3。
              • 你真的不应该在 Swift 3 中使用NSCalendar。使用Calendar。所以这被简化为let calendar = Calendar.current。然后components 看起来像:let components = calendar.dateComponents([.day], from: date1, to: date2)
              【解决方案11】:

              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!
              

              【讨论】:

                【解决方案12】:

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

                【讨论】:

                  【解决方案13】:

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

                  【讨论】:

                    【解决方案14】:

                    这是较短的版本:基本上我现在尝试获取发布时间戳与 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))
                    }
                    

                    【讨论】:

                      【解决方案15】:

                      使用 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
                      }
                      

                      【讨论】:

                        【解决方案16】:

                        我在 Leo Dabus 的 asnwer 中添加了一个“长”版本,以防您想要一个字符串显示“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 ""
                            }
                        
                        }
                        

                        【讨论】:

                          【解决方案17】:

                          你问:

                          我想要一个比较两个日期和 if(seconds > 60) 的函数,然后它返回分钟,if(minutes > 60) 返回小时,if(hours > 24) 返回天等等。

                          我假设您正在尝试构建两个日期之间经过时间的字符串表示形式。与其编写自己的代码来做到这一点,Apple 已经有一个专门为此而设计的类。即,使用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: [])
                          

                          【讨论】:

                            【解决方案18】:
                               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;
                                    }
                            

                            【讨论】:

                            • 尝试延迟加载日期格式化程序,更好的选择是将其设为静态
                            【解决方案19】:

                            如果您的目的是获取两个日期之间的确切天数,您可以像这样解决这个问题:

                            // 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
                            

                            【讨论】:

                              猜你喜欢
                              • 2020-06-13
                              • 1970-01-01
                              • 1970-01-01
                              • 2012-05-19
                              • 1970-01-01
                              相关资源
                              最近更新 更多