14

I want to display NSDates in a "human-friendly way", such as "last week", or "a few days ago". Something similar to Pretty Time for Java.

What's the best way to do this, subclassing NSDateFormatter? Before I go and reinvent the wheel, is there already some library for this?

cfischer
  • 24,452
  • 37
  • 131
  • 214
  • Check the answer to these similar questions: - [Is there some functionality in Cocoa to display time intervals in natural language?](http://stackoverflow.com/questions/2181034/is-there-some-functionality-in-cocoa-to-display-time-intervals-in-natural-languag) - [Is there a way to convert a natural language date NSString to an NSDate](http://stackoverflow.com/questions/5878528/is-there-a-way-to-convert-a-natural-language-date-nsstring-to-an-nsdate) – djromero Jun 13 '11 at 15:31

6 Answers6

40

On iOS 4 and later, use the doesRelativeDateFormatting property:

NSDateFormatter *dateFormatter = ...;
dateFormatter.doesRelativeDateFormatting = YES;
Ilya
  • 5,533
  • 2
  • 29
  • 57
Regexident
  • 29,441
  • 10
  • 93
  • 100
  • 4
    This is perfect. Here's the documentation: http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/Reference/Reference.html#//apple_ref/occ/instm/NSDateFormatter/setDoesRelativeDateFormatting: – Joony Jul 03 '12 at 06:37
  • Perfect if you want a natural language representation of a time interval. eg. iTunes wifi sync settings view on iOS shows "Last sync: Yesterday at 1:06pm" – AFraser Jan 15 '13 at 23:50
  • 1
    This is great but it only works on the date. Not the time (or indeed date/time). i.e. if you want "12 minutes ago", "3 hours ago", "yesterday" then you'll need something else. – Fogmeister Nov 12 '13 at 11:34
  • 1
    @Fogmeister: True, yet OP specifically asked for "human friendly date descriptions". ;) – Regexident Nov 12 '13 at 15:06
  • @Regexident yup, I was looking for the times too though :) hehe :) – Fogmeister Nov 12 '13 at 16:25
6

Three20's NSDateAdditions:

https://github.com/pbo/three20/blob/master/src/Three20Core/Sources/NSDateAdditions.m

.. allows you to do that as well.

EDIT: In 2013, you really don't want to use Three20 anymore. Use Regexident's solution.

magma
  • 8,432
  • 1
  • 35
  • 33
  • 1
    Three20 is **not localized** though. Whereas Apple's `NSDateFormatter` respects local differences (such as in french "the day after the day after tomorrow", see [here](http://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/Classes/NSDateFormatter_Class/Reference/Reference.html#//apple_ref/occ/instm/NSDateFormatter/setDoesRelativeDateFormatting:)). And going english-only is usually a bad idea in the long run. – Regexident Jun 13 '11 at 15:20
  • @regexident you're right. Of course since NSDateAdditions is open source, you can localize it and you have greater control over how it behaves, while NSDateFormatter does it for you and takes the problem off your plate. It's not just that, though; I think they behave quite differently and their output differ. Three20 is - of course - more à-la-facebook. Good observation, though. – magma Jun 13 '11 at 15:28
  • Three20 being open source is a good point (and advantage, no doubt about that, yet a responsibility, too). However NSDataFormatter has the benefit (imho) of always being conform to (and going with) the (possibly shifting) OS standard, without the need of a total rewrite someday in the future. This, plus potential of confusion caused by custom formatters. Should not be a big issue with trivial stuff such as "today/tomorrow/yesterday", but still a point worth taking into consideration, imho. After all the last thing you want is to have your customers confused by your app. – Regexident Jun 13 '11 at 15:35
5

Full code snippet for human readable dates in Xcode:

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setTimeStyle:NSDateFormatterNoStyle];
    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];

    NSLocale *locale = [NSLocale currentLocale];
    [dateFormatter setLocale:locale];

    [dateFormatter setDoesRelativeDateFormatting:YES];
David Douglas
  • 10,377
  • 2
  • 55
  • 53
  • Just for clarification, since this is the best answer. After that we need to do something like [dateFormatter stringFromDate:mydate]; – Alejandro Luengo Nov 22 '17 at 14:40
4

This is the solution in Swift 2:

func formattedHumanReadable(date: NSDate) -> String {
    let formatter = NSDateFormatter()
    formatter.timeStyle = .NoStyle
    formatter.dateStyle = .ShortStyle
    formatter.doesRelativeDateFormatting = true

    let locale = NSLocale.currentLocale()
    formatter.locale = locale

    return formatter.stringFromDate(date)
  }
Allan Scofield
  • 1,884
  • 18
  • 14
  • Swift 4: " func formattedHumanReadable() -> String { let formatter = DateFormatter() formatter.timeStyle = .none formatter.dateStyle = .short formatter.doesRelativeDateFormatting = true formatter.locale = NSLocale.current return formatter.string(from: self) }" – Calin Drule Mar 20 '19 at 16:44
1

A good date formatter is YLMoment, which is based on the popular moment.js.

It does format nice relative times.

samwize
  • 25,675
  • 15
  • 141
  • 186
-2

Use the DateTools (github/Cocoapods) timeAgoSinceNow function. Here's some sample output...

NSDate.init(timeIntervalSinceNow:-3600).timeAgoSinceNow() "An hour ago" NSDate.init(timeIntervalSinceNow:-3600*24).timeAgoSinceNow() "Yesterday" NSDate.init(timeIntervalSinceNow:-3600*24*6).timeAgoSinceNow() "6 days ago" NSDate.init(timeIntervalSinceNow:-3600*24*7*3).timeAgoSinceNow() "3 weeks ago" NSDate.init(timeIntervalSinceNow:-3600*24*31*3).timeAgoSinceNow() "3 months ago"

The timeAgoSinceDate function is also handy.

DateTools supports many (human) languages and gives much better relative descriptions than NSDateFormatter's somewhat limited doesRelativeDateFormatting.

user2067021
  • 4,399
  • 37
  • 44