Getting the difference between two Dates (months/days/hours/minutes/seconds) in Swift

前端 未结 19 2063
时光说笑
时光说笑 2020-11-22 02:16

I am trying to get the difference between the current date as NSDate() and a date from a PHP time(); call for example: NSDate(timeIntervalSin

相关标签:
19条回答
  • 2020-11-22 03:01

    If your purpose is to get the exact day number between two dates, you can work around this issue like this:

    // 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
    
    0 讨论(0)
  • 2020-11-22 03:02
    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
        }
    }
    

    Use:

    var durationString: String {
            return self.endTime.offset(from: self.startTime).dateComponentsToTimeString()
        }
    
    0 讨论(0)
  • 2020-11-22 03:03

    Slightly modified code for 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!
    
    0 讨论(0)
  • 2020-11-22 03:06

    With Swift 3, according to your needs, you may choose one of the two following ways to solve your problem.


    1. Display the difference between two dates to the user

    You can use a DateComponentsFormatter to create strings for your app’s interface. DateComponentsFormatter has a maximumUnitCount property with the following declaration:

    var maximumUnitCount: Int { get set }
    

    Use this property to limit the number of units displayed in the resulting string. For example, with this property set to 2, instead of “1h 10m, 30s”, the resulting string would be “1h 10m”. Use this property when you are constrained for space or want to round up values to the nearest large unit.

    By setting maximumUnitCount's value to 1, you are guaranteed to display the difference in only one DateComponentsFormatter's unit (years, months, days, hours or minutes).

    The Playground code below shows how to display the difference between two dates:

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

    Note that DateComponentsFormatter rounds up the result. Therefore, a difference of 4 hours and 30 minutes will be displayed as 5 hours.

    If you need to repeat this operation, you can refactor your code:

    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. Get the difference between two dates without formatting

    If you don't need to display with formatting the difference between two dates to the user, you can use Calendar. Calendar has a method dateComponents(_:from:to:) that has the following declaration:

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

    Returns the difference between two dates.

    The Playground code below that uses dateComponents(_:from:to:) shows how to retrieve the difference between two dates by returning the difference in only one type of Calendar.Component (years, months, days, hours or minutes).

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

    If you need to repeat this operation, you can refactor your code:

    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
    }
    
    0 讨论(0)
  • 2020-11-22 03:08

    Here is my answer for the Swift 3 answers above. This is current as of Nov 2016, Xcode release was 8.2 Beta (8C23). Used some of both Sagar and Emin suggestions above and sometimes had to let Xcode autocomplete to suggest the syntax. It seemed like the syntax really changed to this beta version. buyDate I got from a 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)")
    
    0 讨论(0)
  • 2020-11-22 03:12

    If someone needs to display all time units e.g "hours minutes seconds" not just "hours". Let's say the time difference between two dates is 1hour 59minutes 20seconds. This function will display "1h 59m 20s".

    Here is my Objective-C code:

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

    In 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 ""
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题