difference between two dates not showing seconds in swift

147 Views Asked by At

enter image description hereI have two dates in Date format.I have used the following code to find the difference between two dates.

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 ""
    }
    func offsetLong(from date: Date) -> String {
        if years(from: date)   > 0 { return years(from: date) > 1 ? "\(years(from: date)) yrs ago" : "\(years(from: date)) yr ago" }
        if months(from: date)  > 0 { return months(from: date) > 1 ? "\(months(from: date)) mo ago" : "\(months(from: date)) mo ago" }
        if weeks(from: date)   > 0 { return weeks(from: date) > 1 ? "\(weeks(from: date)) wks ago" : "\(weeks(from: date)) wk 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)) hrs ago" : "\(hours(from: date)) hr ago"   }
        if minutes(from: date) > 0 { return minutes(from: date) > 1 ? "\(minutes(from: date)) mins ago" : "\(minutes(from: date)) min ago" }
        if seconds(from: date) > 0 { return seconds(from: date) > 1 ? "\(seconds(from: date)) secs ago" : "\(seconds(from: date)) sec ago" }
        return ""
    }
}

I have applied this extension on two dates in EDT timezone and it is as given below:

let dateFormatterGet = DateFormatter()
                       // dateFormatterGet.timeZone = TimeZone(abbreviation: "UTC")
                        dateFormatterGet.dateFormat = "yyyy-MM-dd HH:mm:ss"

                        let dateFormatterPrint = DateFormatter()
                       // dateFormatterPrint.timeZone = TimeZone(abbreviation: "UTC")
                         dateFormatterPrint.dateFormat = "yyyy-MM-dd HH:mm:ss"

                        let date1: Date? = dateFormatterGet.date(from: date) as Date?
                        
                     //   print("date1 is",date1)

                                let now = Date()
                                
                                let dateFormatterGet1 = DateFormatter()
                                dateFormatterGet1.timeZone = TimeZone(abbreviation: "EDT")
                                dateFormatterGet1.dateFormat = "yyyy-MM-dd HH:mm:ss"
                                
                                let dateFormatterPrint1 = DateFormatter()
                                 dateFormatterPrint1.timeZone = TimeZone(abbreviation: "EDT")
                                 dateFormatterPrint1.dateFormat = "yyyy-MM-dd HH:mm:ss"
                                
                                let dat = dateFormatterPrint1.string(from: now) as String
                             
                                           
                                let date2: Date? = dateFormatterGet1.date(from: dat) as Date?
                              
                               let timeOffset3 = date2!.offsetLong(from: date1!)
                               
                                cell2.dateposted.text = timeOffset3

The time offset value is showing till hours, it is not showing in minutes or seconds. Could anyone tell me what is wrong in this conversion?

1

There are 1 best solutions below

2
On

There is a built in class, DateComponentsFormatter, that will create formatted strings from either time intervals or a pair of dates. You configure it with the units you want and the units style you want and it does the rest. It only offers certain pre-set formats (specified with a DateComponentsFormatter.UnitsStyle)

If you want to display the difference between two dates in an arbitrary format then you may need to use the Calendar function dateComponents(_:from:to:). That function takes two dates and a set of the components you want to use, and returns a DateComponents object. You'd then need to write custom code that displayed the value of your DateComponents object in your desired format, which should't be that hard.

It would help if you explained your desired output in your question.

Ok, I looked at the image. It looks like you want a string like "3 minutes ago" "7 hours ago" "Three days ago", "three months ago", etc.

Try code like this:

import Foundation

 var timeFormatter:DateComponentsFormatter = {
    let temp = DateComponentsFormatter()
    temp.allowedUnits = [.year, .month, .weekOfMonth, .day, .hour, .minute, .second]
    temp.maximumUnitCount = 1
    temp.unitsStyle = .full
    return temp
}()

let now = Date()

func timefromDateToNow(_ date: Date) -> String {
    if let output = timeFormatter.string(from: date, to: now) {
        return output + " ago"
    } else {
        return "error"
    }
}

enum Ranges: Int, CaseIterable {
    case seconds
    case minutes
    case hours
    case days
    case weeks
    case months
    case years
}

for _ in 1 ... 20 {
    var min: Double
    var max: Double = 0
    let range = Ranges.allCases.randomElement()!
    switch range {
    case .seconds:
        min = -59.999
    case .minutes: //0 ... 1 hours
        min = -3600
    case .hours: //0 ... 1 day
        min = -86400
    case .days: //0 ... 1 month
        min = -3600 * 24 * 31
    case .weeks:
        min = -3600 * 24 * 31
        max = -3600 * 24 * 7
    case .months:
        min = -3600 * 24 * 365
    case .years: // 0 ... 5 years
        min = -3600 * 24 * 365 * 5
    }
    let past = now.addingTimeInterval(Double.random(in: min ... max))
    print("Range = \(range): \(timefromDateToNow(past))")
}


var units: NSCalendar.Unit

//Note that all 3 methods of populating `units' yields the same value:

print("\nNow show that the order of OptionSet values does not matter:\n")
units = [.year, .second, .month, .hour]
print(units.rawValue)

units = [.second, .hour, .month, .year]
print(units.rawValue)


units = NSCalendar.Unit( rawValue:
                            NSCalendar.Unit.month.rawValue +
                            NSCalendar.Unit.year.rawValue +
                            NSCalendar.Unit.second.rawValue +
                            NSCalendar.Unit.hour.rawValue
)
print(units.rawValue)

That generates output like this:

Range = years: 3 years ago
Range = seconds: 56 seconds ago
Range = months: 9 months ago
Range = minutes: 27 minutes ago
Range = minutes: 34 minutes ago
Range = hours: 15 hours ago
Range = years: 1 year ago
Range = months: 2 months ago
Range = years: 1 year ago
Range = years: 3 years ago
Range = years: 3 years ago
Range = years: 3 years ago
Range = years: 2 months ago
Range = years: 2 years ago
Range = seconds: 59 seconds ago
Range = days: 6 days ago
Range = weeks: 3 weeks ago
Range = years: 11 months ago
Range = hours: 16 hours ago
Range = hours: 7 hours ago

Now show that the order of OptionSet values does not matter:

172
172
172