- Published on
- Tested on Xcode 16.2
- 3 min read
> Showing a relative "Time ago" date in SwiftUI
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.
// Continue_Learning
What's New in SwiftUI for iOS 27
iOS 27 lets you drag to reorder in any container, add swipe actions outside of List, and cache AsyncImage responses. A tour of the headline SwiftUI changes from WWDC 2026, with code.
WWDC 2026 Predictions Report Card: What Apple Actually Shipped
Before WWDC 2026 I wrote down predictions and never hit publish. Four months later, with iOS 27 out and iPhone Duo days away, it's time to grade them against what Apple actually shipped.
iPhone Duo Split View: Is Your Window Left or Right?
When two windows share iPhone Duo's inner display, neither one is told which side it's on. I built a proof of concept in Xcode 27.1 and found the fold's ReservedRegion answers it, once you know its frame is clipped to your window.
// Stay Updated
Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.