1

I've retrieved createdAt column from Parse and i wrote it on UITableview for each row, but the time and date looks like this on tableview :

23-12-2015 01:04:56.380

28-08-2015 19:45:09.101

I want to convert that to time ago for example:

Today 1:04 PM -- Yestarday 5:24 AM -- 3 days ago -- 1 week ago -- 1 month ago

Here is my code:

let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm:ss.SSS"
let date = dateFormatter.stringFromDate((msg.createdAt as NSDate?)!)
Cell.timelbl.text = date

I'm using xcode 7 beta

Any help please?

Salah
  • 933
  • 3
  • 13
  • 32
  • 1
    msg.createdAt returns an optional NSDate. if let date = msg.createdAt { // use date here } – Leo Dabus Dec 23 '15 at 16:12
  • Thanks but can you answer to this and show me how to do it like time ago? i have no idea about that what should i write on //use date here ? – Salah Dec 23 '15 at 16:17
  • 1
    You can use nsdatecomponentsformatter – Leo Dabus Dec 23 '15 at 16:30
  • 1
    Or you can also take a look at this answer http://stackoverflow.com/questions/27182023/getting-the-difference-between-two-nsdates-in-months-days-hours-minutes-seconds/27184261#27184261 – Leo Dabus Dec 23 '15 at 16:31
  • 1
    Or http://stackoverflow.com/a/27337951/2303865 – Leo Dabus Dec 23 '15 at 16:35
  • 1
    You can also take a look at this one http://stackoverflow.com/a/32302797/2303865 – Leo Dabus Dec 23 '15 at 16:40
  • thank you, i'm so confused and getting errors with extension NSDate, Could you show me example how to use that on answer please? – Salah Dec 23 '15 at 16:56
  • 1
    What version is your Xcode ? – Leo Dabus Dec 23 '15 at 17:00
  • Declaration is only valid at file scope, I got this error, Can you edit my code with answer please? – Salah Dec 23 '15 at 17:01
  • 1
    Add a new file to your project (Swift file). Name it Extensions NSDate and put them there – Leo Dabus Dec 23 '15 at 17:01
  • ok I put them on new swift file, And my tableview code looks like this now https://i.gyazo.com/ffa105f3fa32c24349a2dbb346880f53.png what should i do to write the time on timelbl ? – Salah Dec 23 '15 at 17:05
  • 1
    that date var only exists inside that bracket – Leo Dabus Dec 23 '15 at 17:08
  • inside bracket it says " Cannot assign a value of type 'NSDate' to a value of type 'String'? " I'm confused how extension Nsdate in new swift file and my uitableview in other file and how can i write the time like 4 days ago on the timelbl on tableview ? – Salah Dec 23 '15 at 17:15
  • http://stackoverflow.com/a/27337951/2303865 – Leo Dabus Dec 23 '15 at 17:18
  • 1
    Thank you so much !!! worked , I hope you'll get a happy new year :) – Salah Dec 23 '15 at 17:21
  • Months and hours ago worked, but seconds and minutes ago didn't worked, the label will be hidden if the time seconds or mintues, Is there something wrong with the extensions nsdate code? and the time maybe wrong is not counting right, it should be perfect with real device ? – Salah Dec 23 '15 at 17:43

2 Answers2

0

You can use NSCalendar isDateInToday to check if createdAt date is in same day as today, and use isDateInYesterday to check if it was yesterday. Just add a conditional and return a custom string for those conditions, for all other conditions just let date components formatter take care of it for you.

extension Formatter {
        static let time: DateFormatter = {
            let formatter = DateFormatter()
            formatter.calendar = Calendar(identifier: .gregorian)
            formatter.dateFormat = "h:mm a"
            return formatter
        }()
    static let dateComponents: DateComponentsFormatter = {
        let formatter = DateComponentsFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.unitsStyle = .full
        formatter.maximumUnitCount = 1
        formatter.zeroFormattingBehavior = .default
        formatter.allowsFractionalUnits = false
        formatter.allowedUnits = [.year, .month, .weekOfMonth, .day, .hour, .minute, .second]
        return formatter
    }()
}

extension Date {

    var time: String { return Formatter.time.string(from: self) }

    var year:    Int { return Calendar.autoupdatingCurrent.component(.year,   from: self) }
    var month:   Int { return Calendar.autoupdatingCurrent.component(.month,  from: self) }
    var day:     Int { return Calendar.autoupdatingCurrent.component(.day,    from: self) }

    var elapsedTime: String {
        if timeIntervalSinceNow > -60.0  { return "Just Now" }
        if isInToday                 { return "Today at \(time)" }
        if isInYesterday             { return "Yesterday at \(time)" }
        return (Formatter.dateComponents.string(from: Date().timeIntervalSince(self)) ?? "") + " ago"
    }
    var isInToday: Bool {
        return Calendar.autoupdatingCurrent.isDateInToday(self)
    }
    var isInYesterday: Bool {
        return Calendar.autoupdatingCurrent.isDateInYesterday(self)
    }
}

testing:

Calendar.autoupdatingCurrent.date(byAdding: .second, value: -59, to: Date())!
    .elapsedTime        // "Just Now"

Calendar.autoupdatingCurrent.date(byAdding: .minute, value: -1, to: Date())!
    .elapsedTime        // "Today at 5:03 PM"
Calendar.autoupdatingCurrent.date(byAdding: .hour, value: -1, to: Date())!
    .elapsedTime        // "Today at 4:04 PM"

Calendar.autoupdatingCurrent.date(byAdding: .day, value: -1, to: Date())!
    .elapsedTime        // "Yesterday at 5:02 PM"
Calendar.autoupdatingCurrent.date(byAdding: .weekOfYear, value: -1, to: Date())!
    .elapsedTime        // "1 week ago"

Calendar.autoupdatingCurrent.date(byAdding: .month, value: -2, to: Date())!
    .elapsedTime        // "2 months ago"
Calendar.autoupdatingCurrent.date(byAdding: .year, value: -1, to: Date())!
    .elapsedTime        // "1 year ago"
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • I really appreciate that, but i still getting some issue with the code, I just got new message and it says "-14 hours ago" so that's mean seconds\minutes ago not working it keep showing "-14 hours ago" Can you help me to fix that please? And thank you so much! – Salah Dec 24 '15 at 12:47
  • You need to give more info, what date it is returning -14hours? It has to be in the future. – Leo Dabus Dec 24 '15 at 13:09
  • when I sent message at 5AM maybe it says "-14 hours ago" but when i sent at 6AM it showing "Today at 6AM" , have a look here: https://i.gyazo.com/ff3770c53dbf67f1b34d902b5955fd31.png , Can you help me to make it "seconds ago - an hour ago - 3 hours ago - then today at - yestarday at - week ago - month ago " ? – Salah Dec 24 '15 at 14:22
  • @Salah Z means UTC time not your local time. zero seconds from gmt – Leo Dabus Dec 24 '15 at 14:23
  • All you need is to add an IF conditional checking if the time interval it is less than 4 hours just return the date components formatter string – Leo Dabus Dec 24 '15 at 14:27
  • I'm newb with time coding, Can you edit your answer and make seconds\minutes\hours ago please? – Salah Dec 24 '15 at 14:51
  • @Salah sure i could but it would be better for you if I don't. Give it a try, edit your question showing your attempt and what went wrong (or open a new question) I can explain/fix whatever may not work in your attempt – Leo Dabus Dec 24 '15 at 14:55
-1

Wow, the above answer was too much work for me! This is what I did! I think you will find that it's less of a headache on your end!

First go and download and import NSDate-TimeAgo from Kevin Lawler on Github into your project.

If you are using a tableView, which it looks like you are. This is how I did it. Assign a tag to your label in Interface Builder under "Attributes Inspector" (make sure you have your label selected).

Attributes Inspector

In your tableViewController.m file, you will need to find cellForRowAtIndexPath, since you are using Parse, I'm assuming you are using a PFQueryTableViewController, so you will be placing your code inside:

- (PFTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object: (PFObject *)object
{
}

Import NSDate+TimeAgo.h into your tableView.h file and then just place your code inside the curly braces and make sure you return your cell. (note: make sure you have a reference to PFObject like in the above code)

///////////////DATE LABEL (WHEN CREATED)//////////////
//Reference to label in interface builder//
UILabel *myDateLabel = (UILabel*) [cell viewWithTag:103];
//reference to PFObject date of creation from Parse//
NSDate *createdAt = object.createdAt;
//create a string from timeAgo and Parse date//
NSString *timeAgo = [createdAt timeAgo];
//assign string to your label//
myDateLabel.text = timeAgo;
  • thank you so much, but can you do that on Swift ? because i'm using swift only and i have no idea about objective C. – Salah Dec 31 '15 at 19:07
  • Oh man, I'm sorry bro...in that case check out this github project: https://github.com/Toldy/swift-time-ago –  Dec 31 '15 at 19:55
  • I'm not good at swift...but I think this will work? You might have to mess with it a bit to get it working, as I just scribbled it in: `let dateLabel = cell.viewWithTag(103) as? UILabel let dateFormatter = NSDateFormatter() dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss" let parseDate = dateFormatter .stringFromDate(object.createdAt) let timeAgoFormattedDate = NSDate dateTimeFormattedAsTimeAgo: parseDate dateLabel.text = @"%@", timeAgoFormattedDate` –  Dec 31 '15 at 19:56