-->

Finding time between dates in Swift [duplicate]

2019-08-14 02:39发布

问题:

This question already has an answer here:

  • Getting the difference between two NSDates in (months/days/hours/minutes/seconds) 18 answers

Hi Im trying to work out the time between two dates using UIpickers and I am lost. I cannot fathom where to go to on this to get the value to plug into the label. Im not sure if I should use components or before the comparison or just after to put it in the label. Thanks for any pointers.

let calendar = NSCalendar.currentCalendar()
let userCalendar = NSCalendar.currentCalendar()

// Set up date object
let DateMakerFormatter = NSDateFormatter()

let date = NSDate()

@IBOutlet weak var toDatePicker: UIDatePicker!
@IBOutlet weak var fromDatePicker: UIDatePicker!
@IBOutlet weak var dayYearLabel: UILabel!

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}

@IBAction func toDatePickerAction(sender: UIDatePicker) {
var DateFormatter = NSDateFormatter()
DateFormatter.dateFormat = "dd-MM-yyyy HH:mm"
var endTime = DateFormatter.stringFromDate(toDatePicker.date)
self.dayYearLabel.text = endTime
var targetDate = endTime
println("\(endTime)")
}

@IBAction func fromDatePickerAction(sender: UIDatePicker) {
var fromDateFormatter = NSDateFormatter()
fromDateFormatter.dateFormat = "dd-MM-yyyy HH:mm"
var startTime = fromDateFormatter.stringFromDate(fromDatePicker.date)
self.dayYearLabel.text = startTime
var targetDate2 = startTime
println("\(startTime)")
}

@IBAction func getTheDateButton(sender: AnyObject) {
let calendar = NSCalendar.currentCalendar()
let datecomponents = calendar.components(NSCalendarUnit.CalendarUnitSecond,     
fromDate: startTime, toDate: endTime, options: nil)
let second = datecomponents.second
let minute = datecomponents.minute
let hour = datecomponents.hour
let day = datecomponents.day
let year = datecomponents.year


println("Seconds: \(second)")
println("minutes: \(minute)")
println("hours: \(hour)")
println("days: \(day)")
println("years: \(year)")

}


override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}


}

回答1:

You should try using some extensions to help you organize your code. Assuming that you have copied those extensions from the link above, you can do as follow:

class ViewController: UIViewController {

    @IBOutlet weak var timeLabel: UILabel!
    @IBOutlet weak var fromLabel: UILabel!
    @IBOutlet weak var toLabel: UILabel!

    @IBOutlet weak var fromDatePicker: UIDatePicker!
    @IBOutlet weak var toDatePicker: UIDatePicker!

    override func viewDidLoad() {
        super.viewDidLoad()
        fromDatePicker.date = NSDate()
        toDatePicker.date = NSDate().xWeeks(1)
        dateHasChanged()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func dateHasChanged() {
        let fromDate = fromDatePicker.date.earlierDate(toDatePicker.date).zeroSeconds.zeroNanoSeconds
        let toDate   = toDatePicker.date.laterDate(fromDatePicker.date).zeroSeconds.zeroNanoSeconds
        fromLabel.text = fromDate.formatted
        toLabel.text   = toDate.formatted
        timeLabel.text = toDate.offsetFrom(fromDate)
    }
}

As I mentioned here are the extensions from the link above:

extension NSDate {
    func yearsFrom(date:NSDate) -> Int{
        return NSCalendar(calendarIdentifier: NSGregorianCalendar)!.components(NSCalendarUnit.CalendarUnitYear, fromDate: date, toDate: self, options: nil).year
    }
    func monthsFrom(date:NSDate) -> Int{
        return NSCalendar(calendarIdentifier: NSGregorianCalendar)!.components(NSCalendarUnit.CalendarUnitMonth, fromDate: date, toDate: self, options: nil).month
    }
    func weeksFrom(date:NSDate) -> Int{
        return NSCalendar(calendarIdentifier: NSGregorianCalendar)!.components(NSCalendarUnit.CalendarUnitWeekOfYear, fromDate: date, toDate: self, options: nil).weekOfYear
    }
    func daysFrom(date:NSDate) -> Int{
        return NSCalendar(calendarIdentifier: NSGregorianCalendar)!.components(NSCalendarUnit.CalendarUnitDay, fromDate: date, toDate: self, options: nil).day
    }
    func hoursFrom(date:NSDate) -> Int{
        return NSCalendar(calendarIdentifier: NSGregorianCalendar)!.components(NSCalendarUnit.CalendarUnitHour, fromDate: date, toDate: self, options: nil).hour
    }
    func minutesFrom(date:NSDate) -> Int{
        return NSCalendar(calendarIdentifier: NSGregorianCalendar)!.components(NSCalendarUnit.CalendarUnitMinute, fromDate: date, toDate: self, options: nil).minute
    }
    func secondsFrom(date:NSDate) -> Int{
        return NSCalendar(calendarIdentifier: NSGregorianCalendar)!.components(NSCalendarUnit.CalendarUnitSecond, fromDate: date, toDate: self, options: nil).second
    }
    func offsetFrom(date:NSDate) -> String {
        let yearsFromDate   = yearsFrom(date)
        let monthsFromDate  = monthsFrom(date)
        let weeksFromDate   = weeksFrom(date)
        let daysFromDate    = daysFrom(date)
        let hoursFromDate   = hoursFrom(date)
        let minutesFromDate = minutesFrom(date)
        let secondsFromDate = secondsFrom(date)
        if yearsFromDate   > 0 { return "\(yearsFromDate) year"     + { return yearsFromDate   > 1 ? "s" : "" }() }
        if monthsFromDate  > 0 { return "\(monthsFromDate) month"   + { return monthsFromDate  > 1 ? "s" : "" }() }
        if weeksFromDate   > 0 { return "\(weeksFromDate) week"     + { return weeksFromDate   > 1 ? "s" : "" }() }
        if daysFromDate    > 0 { return "\(daysFromDate) day"       + { return daysFromDate    > 1 ? "s" : "" }() }
        if hoursFromDate   > 0 { return "\(hoursFromDate) hour"     + { return hoursFromDate   > 1 ? "s" : "" }() }
        if minutesFromDate > 0 { return "\(minutesFromDate) minute" + { return minutesFromDate > 1 ? "s" : "" }() }
        if secondsFromDate > 0 { return "\(secondsFromDate) second" + { return secondsFromDate > 1 ? "s" : "" }() }
        return ""
    }
}

And you should create another 4 extensions, one for formatting your date as desired, another one to add a calendar unit to your NSDate and two more to zero the seconds and nanoseconds from the date returned by the date pickers:

extension NSDate {
    var formatted: String {
        let styler = NSDateFormatter()
        styler.dateStyle = .FullStyle
        return styler.stringFromDate(self)
    }
    func xWeeks(weeks:Int) -> NSDate {
        return NSCalendar(calendarIdentifier: NSGregorianCalendar)!.dateByAddingUnit(.CalendarUnitWeekOfYear, value: weeks, toDate: self, options: nil)!
    }
    var zeroSeconds: NSDate {
        return NSCalendar(calendarIdentifier: NSGregorianCalendar)!.dateBySettingUnit(.CalendarUnitSecond, value: 0, ofDate: self, options: nil)!
    }
    var zeroNanoSeconds: NSDate {
        return NSCalendar(calendarIdentifier: NSGregorianCalendar)!.dateBySettingUnit(.CalendarUnitNanosecond, value: 0, ofDate: self, options: nil)!
    }
}


回答2:

This could be done in a much simpler way:

let dateA = NSDate() // Current date & time
let dateB = NSDate(timeIntervalSinceNow: -86400) // 1 day ago

let seconds = dateA.timeIntervalSinceDate(dateB) // 86,399.9766479731
let minutes = seconds / 60 // 1,439.99961079955
let hours = minutes / 60 // 23.9999935133259
let days = hours / 24 // 0.99999972972191
let years = days / 365 // 0.00273972528690934

Then just round the values up. Your UIDatePicker already returns a NSDate object. No need to use a date formatter unless you want to print/use the dates in a certain format.