【问题标题】:Swift 3 - find number of calendar days between two datesSwift 3 - 查找两个日期之间的日历天数
【发布时间】:2017-02-25 19:34:03
【问题描述】:

我在 Swift 2.3 中这样做的方式是:

let currentDate         = NSDate()
let currentCalendar     = NSCalendar.currentCalendar()

var startDate : NSDate?
var endDate   : NSDate?

// The following two lines set the `startDate` and `endDate` to the start of the day

currentCalendar.rangeOfUnit(.Day, startDate: &startDate, interval: nil, forDate: currentDate)
currentCalendar.rangeOfUnit(.Day, startDate: &endDate, interval: nil, forDate: self)

let intervalComps = currentCalendar.components([.Day], fromDate: startDate!, toDate: endDate!, options: [])

print(intervalComps.day)

现在这一切都随着 Swift 3 改变了。我必须要么使用 NSCalendarNSDate 通过不断地使用 as 进行类型转换,要么找到 Swift 3 的方法。

在 Swift 3 中正确的做法是什么?

【问题讨论】:

  • 使用DateCalendar。查看两者的参考文档以查看 API 更改。做一次尝试。用您尝试过的内容更新您的问题,并解释您在翻译中可能遇到的任何问题。

标签: nsdate swift3 nscalendar


【解决方案1】:

Swift 5 中,有一个简单的单行器可以获取两个日期之间的天数(或任何其他 DateComponent):

let diffInDays = Calendar.current.dateComponents([.day], from: dateA, to: dateB).day

注意:正如 cmets 中所指出的,此解决方案测量 24 小时周期,因此在 dateAdateB 之间至少需要 24 小时。

【讨论】:

  • 这对我不起作用,因为它需要每天 24 小时。
  • 警告:这给出了两个日期之间的 24 小时周期数,向下舍入。最初的问题是询问日历天数的差异,解决方案在 Vinod 的回答中。
  • @Kqtr 将 "dateA" 和 "dateB" 替换为 calendar.startOfDay(for: dateA)calendar.startOfDay(for: dateB)
  • 需要将 diffInDays 除以 24,例如 diffInDays/24 = 天数
【解决方案2】:

事实证明,这在 Swift 3 中要简单得多:

extension Date {    

    func interval(ofComponent comp: Calendar.Component, fromDate date: Date) -> Int {

        let currentCalendar = Calendar.current

        guard let start = currentCalendar.ordinality(of: comp, in: .era, for: date) else { return 0 }
        guard let end = currentCalendar.ordinality(of: comp, in: .era, for: self) else { return 0 }

        return end - start
    }
}

编辑

比较两个日期的序数应该在同一个era而不是同一个year,因为自然这两个日期可能在不同的年份。

用法

let yesterday = Date(timeInterval: -86400, since: Date())
let tomorrow = Date(timeInterval: 86400, since: Date())


let diff = tomorrow.interval(ofComponent: .day, fromDate: yesterday)
// return 2

【讨论】:

  • 结束变量有参数“self”,这应该等于什么?我尝试在自定义类中使用您的函数来获取日期和用户输入的日期之间的天数,但 self 不起作用。
  • 我已经用示例用法更新了我的答案。给定的代码旨在用作实例方法(可以通过在 Date 的扩展中添加函数来完成)。
  • 很棒的扩展!非常适合任何日期类型的任何间隔,正是我正在寻找的:)。对于想要更轻松地添加未来日期的其他人,请尝试此操作, var components = DateComponents() components.setValue(numOfDays, for: .day) let futureDate = Calendar.current.date(byAdding: components, to: dateChosen), dateChosen 是就这样,让 dateChosen: Date = Date()
  • 小心:这似乎不适用于某些时区,例如 UTC+05:30。我怀疑这会告诉您这两个日期是否在时代开始以来的同一 24 小时内,并且时代的开始是特定时区的午夜(UTC?)。所以它基本上忽略了日历的时区。我最终创建了一个愚蠢的自定义实用程序方法,它比较两个日期的“yyyy-MM-dd”并添加/删除一天,直到找到相同的字符串。
  • 我发现要解决时区问题(我的时区中的两个日期时间“今天”在计算时区中的“不同日期”中)当我使用将两个输入日期转换为午夜时,我得到了更好的结果日历.startOfDay。我在上面加上了这个://午夜一天...让午夜1 = DateTimeHelper.midnight(日期:日期1)让午夜2 = DateTimeHelper.midnight(日期:日期2)
【解决方案3】:

Swift 4 版本

let startDate = "2000-11-22"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let formatedStartDate = dateFormatter.date(from: startDate)
let currentDate = Date()
let components = Set<Calendar.Component>([.second, .minute, .hour, .day, .month, .year])
let differenceOfDate = Calendar.current.dateComponents(components, from: formatedStartDate!, to: currentDate)

print (differenceOfDate)

印刷 - 年:16 月:10 日:19 时:12 分:16 秒:42 isLeapMonth:false

【讨论】:

  • 我怎样才能只得到一天?
  • @Rob : 去掉 let components = Set... 直接使用 let differenceOfDate = Calendar.current.dateComponents([.day], from: formatedStartDate!, to:当前日期)
【解决方案4】:

如果有人想更具体地执行以下步骤

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 amount of nanoseconds from another date
func nanoseconds(from date: Date) -> Int {
    return Calendar.current.dateComponents([.nanosecond], from: date, to: self).nanosecond ?? 0
}
/// Returns the a custom time interval description from another date
func offset(from date: Date) -> String {
    var result: 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 seconds(from: date) > 0 { return "\(seconds(from: date))" }
            if days(from: date)    > 0 { result = result + " " + "\(days(from: date)) D" }
            if hours(from: date)   > 0 { result = result + " " + "\(hours(from: date)) H" }
            if minutes(from: date) > 0 { result = result + " " + "\(minutes(from: date)) M" }
           if seconds(from: date) > 0 { return "\(seconds(from: date))" }
    return ""
 }
}

2.全局定义

 fileprivate var timer: Timer?

3.在 viewDidLoad 或任何你想要的地方调用这个方法

override func viewDidLoad() {
    super.viewDidLoad()
    self.getRemainingTime()
} 

4.用法

fileprivate func getRemainingTime() {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

    let startDate = "2018-06-02 10:11:12"
    let currentDate = dateFormatter.string(from: Date())

    if currentDate != startDate {
        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(calculateTime)), userInfo: nil, repeats: true)
        RunLoop.current.add(timer!, forMode: RunLoopMode.commonModes)
        timer?.fire()
    }
    else {
        self.timer?.invalidate()
        self.timer = nil
    }
}

func calculateTime() {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

    let stdate : String = "2018-06-02 10:11:12"
    let startDate = dateFormatter.date(from: stdate)!

    let currentDate = Date()

    let strTimer : String = startDate.offset(from: currentDate)
    if !strTimer.isEmpty {
        let stDay: String = "\((Int(strTimer)! % 31536000) / 86400)"
        let stHour: String = "\((Int(strTimer)! % 86400) / 3600)"
        let stMin: String = "\((Int(strTimer)! % 3600) / 60)"
        let stSec: String = "\(Int(strTimer)! % 60)"
        yourLabelOutlet.text = "Start In :\(stDay) Days \(stHour) Hours \(stMin) Minutes \(stSec) Seconds"
    }

}

像 Charm 一样工作您可以在 UI 端使用每个单独的字符串, 享受

【讨论】:

  • 我没看懂这段代码 let stMin: String = "((Int(strTimer)! % 3600) / 60)"。你为什么要做模和除函数
【解决方案5】:
private func calculateDaysBetweenTwoDates(start: Date, end: Date) -> Int {

    let currentCalendar = Calendar.current
    guard let start = currentCalendar.ordinality(of: .day, in: .era, for: start) else {
        return 0
    }
    guard let end = currentCalendar.ordinality(of: .day, in: .era, for: end) else {
        return 0
    }
    return end - start
}

【讨论】:

    【解决方案6】:

    在 Swift4 中,我们可以使用以下代码轻松获取两个不同日历日期之间的天数。

    第一个是与当前日期的天数差。

    let previousDate = "2017-03-01"
    let currentDate = Date()
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd"
    let previousDateFormated : Date? = dateFormatter.date(from: previousDate)
    let difference = currentDate.timeIntervalSince(previousDateFormated!)
    var differenceInDays = Int(difference/(60 * 60 * 24 ))
    print(differenceInDays)
    

    继续上面的代码...下面是查找两个不同日期的天数。前一个日期的内容取自上述日期

    let futureDate = "2017-12-30"
    let futureDateFormatted : Date? = dateFormatter.date(from: futureDate)
    differenceInDays = (futureDateFormatted?.timeIntervalSince(previousDateFormated!))! / (60 * 60 * 24)
    
    print(differenceInDays)
    

    【讨论】:

      【解决方案7】:

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

      这是我的代码:

      let dateFormatter = DateFormatter()
      dateFormatter.dateFormat = "yyyy-MM-dd'T'hh:mm:ss"
      let start = dateFormatter.date(from: "2019-01-31T07:45:00")!
      let end = dateFormatter.date(from: "2019-03-01T06:30:00")!
      print("Date Difference :   ", end.offsetFrom(date: start))
      

      功能定义:

      extension Date {
      
          func offsetFrom(date : Date) -> String {
      
              let dayHourMinuteSecond: Set = [.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 ""
          }
      }
      

      【讨论】:

      • 酷,这就是我想要的!我们也为新的 Apple Swift 5.1.3 版本更新了它。
      【解决方案8】:

      在另一个线程上找到了这个,但它最终是我使用 Swift 4 最简单的解决方案:

      let previousDate = ENTER DATE HERE
      let now = Date()
      
      let formatter = DateComponentsFormatter()
      formatter.unitsStyle = .brief // May delete the word brief to let Xcode show you the other options
      formatter.allowedUnits = [.month, .day, .hour]
      formatter.maximumUnitCount = 1   // Show just one unit (i.e. 1d vs. 1d 6hrs)
      
      let stringDate = formatter.string(from: previousDate, to: now)
      

      【讨论】:

      • 我认为这个答案很好。如果目的是在 UI 中显示两个日期之间经过的天数(或天数和月数或小时和秒数或其他),那么这是一个很好的方法。 DateComponentsFormatter 生成本地化字符串,非常强大和灵活。
      • 谢谢 Rob - 更新以消除我回答的后半部分无用的问题。
      • 不错的简单答案!对于其他读者,如果您希望以简短形式显示月、日或小时,请将 formatter.unitsStyle 更改为 .abbreviated 而不是 .brief
      【解决方案9】:
      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()
          }
      

      【讨论】:

        【解决方案10】:
        private func days(actual day1:[Int],expect day2:[Int]) -> Int {
        
                let dateFormatter = DateFormatter()
                dateFormatter.dateFormat = "yyyy-MM-dd"
        
                let first = "\(day1[2])-\(day1[1])-\(day1[0])"
                let firstDate = dateFormatter.date(from:first)!
                let last = "\(day2[2])-\(day2[1])-\(day2[0])"
                let lastDate = dateFormatter.date(from:last)!
        
                let currentCalendar = NSCalendar.current
        
                let components = currentCalendar.dateComponents([.day], from: firstDate, to: lastDate)
        
                return components.day!
            }
        

        另一种比较日月年成分的方法

        用法:

        按以下格式输入日期

        [dd, mm, yyyy]
        [9, 6, 2017]
        [6, 6, 2017]
        

        【讨论】:

          【解决方案11】:

          为 Swift 3 更新:

          如果要打印两个日历日期之间的天数以及天数列表,请使用以下简单代码;

          // 变量声明:

          var daysListArray = [String]()
          

          //函数定义:

          func printCountBtnTwoDates(mStartDate: Date, mEndDate: Date) -> Int {
              let calendar = Calendar.current
              let formatter = DateFormatter()
              var newDate = mStartDate
              daysListArray.removeAll()
          
              while newDate <= mEndDate {
                  formatter.dateFormat = "yyyy-MM-dd"
                  daysListArray.append(formatter.string(from: newDate))
                  newDate = calendar.date(byAdding: .day, value: 1, to: newDate)!
              }
             // print("daysListArray: \(daysListArray)") // if you want to print list between start date and end date
              return daysListArray.count
          }
          

          // 调用上述函数:

              let count = self.printCountBtnTwoDates(mStartDate: your_start_date, mEndDate: your_end_date)
              print("count: \(count)") // date count
          

          // 享受编码...!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-05-10
            • 2016-03-15
            • 2017-05-17
            相关资源
            最近更新 更多