Swift convert time to time ago

Salah picture Salah · Dec 24, 2015 · Viewed 18.1k times · Source

In Swift5, we have RelativeDateTimeFormatter

Prior to Swift5:


I'm trying to convert time to time ago, what i wanna do is:

from 1 to 15 seconds it will say " Just now "

from 60 minutes to 119 minutes it will say " an hour ago "

from 24 hours to 47 hours it will say " Yesterday "

from 7 days to 7 days and 23 hours it will say " a week ago "

I'm not sure about my counting if am i wrong feel free to fix it for me

Here is the code

    extension NSDate {

    struct Date {
        static let timeFormatter: NSDateFormatter = {
            let df = NSDateFormatter()
            df.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
            df.dateFormat = "h:mm a"
            return df
            }()
    }
    var time: String { return Date.timeFormatter.stringFromDate(self) }

    var year:    Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Year,   fromDate: self) }
    var month:   Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Month,  fromDate: self) }
    var day:     Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Day,    fromDate: self) }
    var hour:     Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Hour,    fromDate: self) }
    var minute:     Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Minute,    fromDate: self) }
    var second:     Int { return NSCalendar.autoupdatingCurrentCalendar().component(.Second,    fromDate: self) }


    struct DateComponents {
        static let formatter: NSDateComponentsFormatter = {
            let dcFormatter = NSDateComponentsFormatter()
            dcFormatter.calendar = NSCalendar(identifier: NSCalendarIdentifierISO8601)!
            dcFormatter.unitsStyle = .Full
            dcFormatter.maximumUnitCount = 1
            dcFormatter.zeroFormattingBehavior = .Default
            dcFormatter.allowsFractionalUnits = false
            dcFormatter.allowedUnits = [.Year, .Month, .Weekday, .Day, .Hour, .Minute, .Second]
            return dcFormatter
            }()
    }

    var elapsedTime: String {


        if isecond(NSDate()) {
            return "Just now"

        }

        if ishour(NSDate()) {
           return "an hour ago"

        }
        if isyesterday(NSDate()) {
            return "Yesterday"
        }
        if isweek(NSDate()) {

            return "a week ago"
        }




        return (DateComponents.formatter.stringFromTimeInterval(NSDate().timeIntervalSinceDate(self)) ?? "") + " ago"
    }
    func isyesterday(date: NSDate) -> Bool {
        return  NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.yesterday)
    }
    var yesterday: NSDate {
        return  NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: day-1, hour: 0, minute: 0, second: 0, nanosecond: 0)!
    }



    func isweek(date: NSDate) -> Bool {
        return  NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.weekago)
    }
    var weekago: NSDate {
        return  NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: day-7, hour: 0, minute: 0, second: 0, nanosecond: 0)!
    }

    func isecond(date: NSDate) -> Bool {
        return  NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.secondsago)
    }
    var secondsago: NSDate {
        return  NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: 0, hour: 0, minute: 0, second: second-15, nanosecond: 0)!
    }

    func ishour(date: NSDate) -> Bool {
        return  NSCalendar.autoupdatingCurrentCalendar().isDate(self, inSameDayAsDate: date.hourago)
    }
    var hourago: NSDate {
        return  NSCalendar.autoupdatingCurrentCalendar().dateWithEra(1, year: year, month: month, day: 0, hour: hour-1, minute: minute-1, second: 0, nanosecond: 0)!
    }
}

here what i got in my app : enter image description here

the quotes which is "an hour ago" , " Just now", etc not showing, only " Yesterday" and i'm not sure if it is from 7 days to 23 hours only!

and here is my first question link : Swift How to convert Parse createdAt time to time ago?

Please help me to fix the code, thanks to @Leo Dabus for the code.

Answer

Sonia Casas picture Sonia Casas · Nov 8, 2016

I'll just update the Truongky's answer for Swif 3:

extension Date {

func getElapsedInterval() -> String {

    let interval = Calendar.current.dateComponents([.year, .month, .day], from: self, to: Date())

    if let year = interval.year, year > 0 {
        return year == 1 ? "\(year)" + " " + "year ago" :
            "\(year)" + " " + "years ago"
    } else if let month = interval.month, month > 0 {
        return month == 1 ? "\(month)" + " " + "month ago" :
            "\(month)" + " " + "months ago"
    } else if let day = interval.day, day > 0 {
        return day == 1 ? "\(day)" + " " + "day ago" :
            "\(day)" + " " + "days ago"
    } else {
        return "a moment ago"

    }

}
}

If you prefer a localizable response instead of only english this code will do the work

extension Date {
func getElapsedInterval() -> String {

    var calendar = Calendar.current
    calendar.locale = Locale(identifier: Bundle.main.preferredLocalizations[0]) 
// IF THE USER HAVE THE PHONE IN SPANISH BUT YOUR APP ONLY SUPPORTS I.E. ENGLISH AND GERMAN
// WE SHOULD CHANGE THE LOCALE OF THE FORMATTER TO THE PREFERRED ONE 
// (IS THE LOCALE THAT THE USER IS SEEING THE APP), IF NOT, THIS ELAPSED TIME 
// IS GOING TO APPEAR IN SPANISH

    let formatter = DateComponentsFormatter()
    formatter.unitsStyle = .full
    formatter.maximumUnitCount = 1
    formatter.calendar = calendar

    var dateString: String?

    let interval = calendar.dateComponents([.year, .month, .weekOfYear, .day], from: self, to: Date())

    if let year = interval.year, year > 0 {
        formatter.allowedUnits = [.year] //2 years
    } else if let month = interval.month, month > 0 {
        formatter.allowedUnits = [.month] //1 month
    } else if let week = interval.weekOfYear, week > 0 {
        formatter.allowedUnits = [.weekOfMonth] //3 weeks
    } else if let day = interval.day, day > 0 {
        formatter.allowedUnits = [.day] // 6 days
    } else {
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: Bundle.main.preferredLocalizations[0]) //--> IF THE USER HAVE THE PHONE IN SPANISH BUT YOUR APP ONLY SUPPORTS I.E. ENGLISH AND GERMAN WE SHOULD CHANGE THE LOCALE OF THE FORMATTER TO THE PREFERRED ONE (IS THE LOCALE THAT THE USER IS SEEING THE APP), IF NOT, THIS ELAPSED TIME IS GOING TO APPEAR IN SPANISH
        dateFormatter.dateStyle = .medium
        dateFormatter.doesRelativeDateFormatting = true

        dateString = dateFormatter.string(from: self) // IS GOING TO SHOW 'TODAY'
    }

    if dateString == nil {
        dateString = formatter.string(from: self, to: Date())
    }

    return dateString!
}