New Text Formatters in iOS 18

Chase
3 min readJun 11, 2024

--

Reference, Offset, and Timers, are new text formatters to iOS 18 and they make displaying dates even easier and more powerful.

A screenshot of the new ios 18 text formatters that were released as part of WWDC 2024

Before we get started, please take a couple of seconds to follow me and 👏 clap for the article so that we can help more people learn about this useful content.

Jumping straight to the code

One quick note before we get started, you will need Xcode 16 which was released during WWDC 2024.

The code below is broken up into sections that each hold some examples of the new text formatters that we get to use in iOS 18 and Xcode 16.

//  ContentView.swift
import SwiftUI

struct ContentView: View {
let calendar = Calendar.current
@State var now = Date.now

var body: some View {
List {
Section("References") {
Text(now, format: .reference(to: wwdcStartDate()))
Text(
now,
format: .reference(
to: wwdcStartDate(),
allowedFields: [.year, .month, .week, .day, .hour, .minute, .second],
maxFieldCount: 7,
thresholdField: .second
)
)

// note that this is different from the offset and
// adds the word "ago" to the time difference in seconds
Text(
now,
format: .reference(
to: wwdcStartDate(),
allowedFields: [.second],
maxFieldCount: 7,
thresholdField: .second
)
)
}

Section("Offsets") {
Text(now, format: .offset(to: wwdcStartDate()))
Text(
now,
format: .offset(
to: wwdcStartDate(),
allowedFields: [.year, .month, .day, .hour, .minute, .second],
maxFieldCount: 6
)
)

// this option simply displays the amount of seconds difference
// without the added context
Text(
now,
format: .offset(
to: wwdcStartDate(),
allowedFields: [.second],
maxFieldCount: 6
)
)
}

Section("Timers") {
// note that range requires the date on the lower end be less
// than the one on the upper end, otherwise it will crash
Text(now, format: .timer(countingUpIn: wwdcStartDate()..<now))

// even though this option allows us to choose nanoseconds,
// it appears to stop displaying text at the millisecond level
Text(
now,
format: .timer(
countingUpIn: wwdcStartDate()..<now,
maxFieldCount: 100,
maxPrecision: .nanoseconds(1)
)
)
Text(
now,
format: .timer(
countingUpIn: wwdcStartDate()..<now,
maxFieldCount: 100,
maxPrecision: .milliseconds(1)
)
)
// this appears to lock the timer to zero once the event has passed
Text(now, format: .timer(countingDownIn: wwdcStartDate()..<now))
}

Button("Get New Time") {
getCurrentDateTime()
}.padding(.vertical)
}
}

func wwdcStartDate() -> Date {
var components = DateComponents()
components.year = 2024
components.month = 6
components.day = 10
components.hour = 10
components.minute = 0

return calendar.date(from: components)!
}

func getCurrentDateTime() {
now = Date.now
}
}

#Preview {
ContentView()
}

If want to know more about formatting dates and times in iOS 17 and earlier, check out another article I wrote here: https://medium.com/@jpmtech/swiftui-format-dates-and-times-the-easy-way-fc896b25003b

If you got value from this article, please consider following me, 👏 clapping for this article, or sharing it to help others more easily find it.

If you have any questions on the topic or know of another way to accomplish the same task, feel free to respond to the post or share it with a friend and get their opinion on it. If you want to learn more about native mobile development, you can check out the other articles I have written here: https://medium.com/@jpmtech. If you want to see apps that have been built with native mobile development, you can check out my apps here: https://jpmtech.io/apps. Thank you for taking the time to check out my work!

--

--