BS
BleepingSwift
Published on

> Showing a relative "Time ago" date in SwiftUI

Authors
  • avatar
    Name
    Mick MacCallum
    Twitter
    @0x7fs

Displaying dates as "5 minutes ago" or "yesterday" instead of raw timestamps makes your app feel more conversational and easier to scan. Foundation's RelativeDateTimeFormatter handles this out of the box, with full localization support and several formatting styles to match your UI's tone.

Basic Usage

The formatter compares two dates and produces a human-readable string describing their relationship:

let pastDate = Date.now.addingTimeInterval(-3600) // 1 hour ago
let formatter = RelativeDateTimeFormatter()
let relative = formatter.localizedString(for: pastDate, relativeTo: Date.now)
// "1 hour ago"

For future dates, the formatter automatically adjusts the phrasing:

let futureDate = Date.now.addingTimeInterval(86400) // 24 hours from now
formatter.localizedString(for: futureDate, relativeTo: Date.now)
// "in 1 day"

Customizing the Output Style

The formatter has two main properties that control its output: unitsStyle and dateTimeStyle.

The unitsStyle property determines how units are displayed. The default is .full, but you have several options:

let date = Date.now.addingTimeInterval(-7200) // 2 hours ago

formatter.unitsStyle = .full
// "2 hours ago"

formatter.unitsStyle = .short
// "2 hr. ago"

formatter.unitsStyle = .abbreviated
// "2 hr. ago"

formatter.unitsStyle = .spellOut
// "two hours ago"

The dateTimeStyle property controls whether the formatter uses numeric values or named references like "yesterday". The default is .numeric:

let yesterday = Date.now.addingTimeInterval(-86400)

formatter.dateTimeStyle = .numeric
// "1 day ago"

formatter.dateTimeStyle = .named
// "yesterday"

Named style works well for recent dates where terms like "yesterday" or "last week" feel natural. For older dates or when you need consistency, numeric style is more predictable.

Handling Capitalization

The formattingContext property handles capitalization based on where the text appears in a sentence:

formatter.formattingContext = .beginningOfSentence
// "In 5 minutes"

formatter.formattingContext = .middleOfSentence
// "in 5 minutes"

formatter.formattingContext = .standalone
// Default context

This is particularly useful when you're building sentences dynamically or displaying the relative time in different UI contexts.

Using It in SwiftUI

Here's a simple Text view that displays a relative timestamp:

struct TimeAgoText: View {
    let date: Date

    private var relativeString: String {
        let formatter = RelativeDateTimeFormatter()
        formatter.unitsStyle = .full
        return formatter.localizedString(for: date, relativeTo: Date.now)
    }

    var body: some View {
        Text(relativeString)
    }
}

For timestamps that should update automatically, you can use a timer to refresh the view:

struct LiveTimeAgoText: View {
    let date: Date
    @State private var now = Date.now

    private let timer = Timer.publish(every: 60, on: .main, in: .common).autoconnect()

    private var relativeString: String {
        let formatter = RelativeDateTimeFormatter()
        formatter.unitsStyle = .full
        return formatter.localizedString(for: date, relativeTo: now)
    }

    var body: some View {
        Text(relativeString)
            .onReceive(timer) { _ in
                now = Date.now
            }
    }
}

Localization

The formatter automatically respects the user's locale settings, but you can override it if needed:

let formatter = RelativeDateTimeFormatter()
formatter.locale = Locale(identifier: "es")
formatter.localizedString(for: date, relativeTo: Date.now)
// "hace 2 horas"

This makes RelativeDateTimeFormatter ideal for apps that support multiple languages—you get properly localized relative times without maintaining translation tables for time units.

When to Use Something Else

RelativeDateTimeFormatter works best for recent dates within the past few months. For older dates, the output becomes less useful ("52 weeks ago" isn't particularly helpful). Consider falling back to a standard date format for anything older than a reasonable threshold, or use a combination approach where recent items show relative times and older items show actual dates.

subscribe.sh

// Stay Updated

Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.

>

By subscribing, you agree to our Privacy Policy.