IOS developer based in barcelona.

DateFormatter to display relative dates: today, yesterday, etc

Last week I created a date formatter to display relative dates. Basically, when I get a date I need to create a string with the relative date: today, yesterday, etc and if the date can't be relative,  I must show a custom date, for instance Jan 18, 2018. Besides, It needs to be localized, for example in french would be aujourd’huihier or avant-hier.


So, imagine that we receive the following date from our backend

let stringDate = "2018-01-18T16:29:30Z"

First of all, we are gonna create a basic formatter to get an instance of Date

let formatter = DateFormatter()
formatter.locale = locale
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZ"
let date = formatter.date(from: stringDate)
// "Jan 18, 2018 at 5:29 PM"

Then, we create two simple functions, the first one creates a DateFormatter, and the second one returns a string from a date

func buildFormatter(locale: Locale, hasRelativeDate: Bool = false, dateFormat: String? = nil) -> DateFormatter {
    let formatter = DateFormatter()
    formatter.timeStyle = .none
    formatter.dateStyle = .medium
    if let dateFormat = dateFormat { formatter.dateFormat = dateFormat }
    formatter.doesRelativeDateFormatting = hasRelativeDate
    formatter.locale = locale
    return formatter
}

func dateFormatterToString(_ formatter: DateFormatter, _ date: Date) -> String {
    return formatter.string(from: date)
}

Now, we can create our different date formatters, the first one would be the relative date formatter, the second one would be the non relative date formatter (we are gonna use it only to compare the date with the relative date formatter), and finally, we are gonna create a date formatter to display in our app just in case the previous dates from the relative and non relative formatter are equal.

So, as we mentioned, we create the third date formatter and we check if the relative date is equal to the non relative date. If they are equals, we are gonna use the custom date formatter, and if they are different we are gonna use the relative date. 

If they are different, it means that the result from the relative date formatter could be "Today" and the date from the non relative formatter could be "Jan 18, 2018" (so they are different)
let relativeFormatter = buildFormatter(locale: locale, hasRelativeDate: true)
let relativeDateString = dateFormatterToString(relativeFormatter, date!)
// "Jan 18, 2018"

let nonRelativeFormatter = buildFormatter(locale: locale)
let normalDateString = dateFormatterToString(nonRelativeFormatter, date!)
// "Jan 18, 2018"

let customFormatter = buildFormatter(locale: locale, dateFormat: "DD MMMM")
let customDateString = dateFormatterToString(customFormatter, date!)
// "18 January"

if relativeDateString == normalDateString {
    print("Use custom date \(customDateString)") // Jan 18
} else {
    print("Use relative date \(relativeDateString)") // Today, Yesterday
}

Conclusion

Today, in a very basic way I've explained to you how relative dates can be created. You can avoid creating boilerplate code to handle basic relative dates with different localizations (english, french, spanish...) because you get for free using the current local identifier from user's device.

I'm all ears to know your feedback, thanks for reading! 😃

UIButton with Right Image

Using Set in Swift