iOS and macOS contain built in support for various ways to format dates, such as for human readable text and to show intervals between dates.

At WWDC19, Apple added a new RelativeDateTimeFormatter , which formats relative dates from the current date, for example by formatting a past date as “X days ago” or today as “today”.

This guide explores how to display and format dates using many of the different date formatters built into Apple’s platforms.

Setup

As all of the built in date formatters are available in Apple’s Foundation framework, no installation is required to use them. However, make sure to add import Foundation to the top of your file to be able to use them in your code.

If you’d like to follow along with this guide, just create a Swift Playground using Xcode or the Swift Playgrounds app for iPad.

Additionally, you can click any of the class or header names to go to Apple’s official Developer Documentation.

Formatting basic dates is easy with DateFormatter . It supports many different time and date styles, allowing you to get the format that you want.

Just create a formatter and set its time and date style to use it:

let formatter = DateFormatter () formatter . timeStyle = . short formatter . dateStyle = . short let currentDate = Date () formatter . string ( from : currentDate ) // 21/7/2019, 9:41 AM

DateFormatter can be used with either a date or time style, or both.

None

The .none style ignores the date and only uses the time style.

formatter . dateStyle = . none formatter . string ( from : currentDate )

Short

The .short style only uses numbers without text.

formatter . dateStyle = . short formatter . string ( from : currentDate ) // 21/7/2019

Medium

The .medium style is more human readable and uses the short name of the month.

formatter . dateStyle = . medium formatter . string ( from : currentDate ) // 21 Jul 2019

Long

The .long style is the same as the medium style but slightly longer, using the full name of the month.

formatter . dateStyle = . long formatter . string ( from : currentDate ) // 21 July 2019

Full

The .full style displays the entire date, including the name of the week.

formatter . dateStyle = . full formatter . string ( from : currentDate ) // Sunday, 21 July 2019

None

The .none style ignores the time and only uses the date style.

formatter . timeStyle = . none formatter . string ( from : currentDate )

Short

The .short style is the simplest time style and just shows the hours, minutes, and whether it is currently AM or PM.

formatter . timeStyle = . short formatter . string ( from : currentDate ) // 9:41 AM

Medium

The .medium style is the same as the short style but also displays seconds.

formatter . timeStyle = . medium formatter . string ( from : currentDate ) // 9:41:00 AM

Long

The .long style is the same as the short style but also displays the time zone.

formatter . timeStyle = . long formatter . string ( from : currentDate ) // 9:41:00 AM GMT+2

Full

The .full style displays everything from the other time styles as well as the entire name of the time zone.

formatter . timeStyle = . full formatter . string ( from : currentDate ) // 9:41:00 AM Central European Summer Time





DateComponentsFormatter formats DateComponents instances, which contain dates and times specified in terms of units.

Just create a formatter and pass an instance of DateComponents , and the formatter will represent the components the best it can.

let formatter = DateComponentsFormatter () let components = DateComponents ( hour : 9 , minute : 41 ) formatter . string ( from : components ) // 9:41

DateComponentsFormatter contains five unit styles, which format the date components in different ways.

formatter . unitsStyle = . positional // .positional, .abbreviated, .short, .full or .spellOut

Positional

The .positional style is the default style, and uses typical date position formatting instead of separating each component like the abbreviated style.

formatter . unitsStyle = . positional formatter . string ( from : components ) // 9:41

Abbreviated

The .abbreviated style is the shortest style apart from the positional style and abbreviates the components as much as possible.

formatter . unitsStyle = . abbreviated formatter . string ( from : components ) // 9h 41m

Short

The .short style uses slightly longer versions of each date component.

formatter . unitsStyle = . short formatter . string ( from : components ) // 9hr 41min

Full

The .full style uses the full name for each date component.

formatter . unitsStyle = . full formatter . string ( from : components ) // 9 hours, 41 minutes

Spelled Out

The .spellOut style is the longest style and uses spelled out versions of everything.

formatter . unitsStyle = . spellOut formatter . string ( from : components ) // Nine hours, forty-one minutes





DateIntervalFormatter is similar to the basic DateFormatter , but it displays both a beginning and end date, such as 21-26 July 2019 .

To use it, create a formatter and generate a string from two dates:

let formatter = DateIntervalFormatter () let currentDate = Date () let twoMinutesAgo = Calendar . current . date ( byAdding : . minute , value : - 2 , to : currentDate ) ?? currentDate formatter . string ( from : currentDate , to : twoMinutesAgo ) // 21/7/2019, 9:41-9:43 AM let fiveDaysAway = Calendar . current . date ( byAdding : . day , value : 5 , to : currentDate ) ?? currentDate formatter . string ( from : currentDate , to : fiveDaysAway ) // 21/7/2019, 9:41 AM - 26/7/2019, 9:43 AM

Note that by default, the output will be based on the locale and time style from the device preferences, so you might see something different.

DateIntervalFormatter uses the same date styles that the basic date formatter does. Here are examples of each style:

formatter . dateStyle = . none formatter . string ( from : currentDate , to : fiveDaysAway ) formatter . dateStyle = . short formatter . string ( from : currentDate , to : fiveDaysAway ) // 21/7/2019-26/7/2019 formatter . dateStyle = . medium formatter . string ( from : currentDate , to : fiveDaysAway ) // 21-26 Jul 2019 formatter . dateStyle = . long formatter . string ( from : currentDate , to : fiveDaysAway ) // 21-26 July 2019 formatter . dateStyle = . full formatter . string ( from : currentDate , to : fiveDaysAway ) // Sunday, 21-Friday, 26 July 2019

DateIntervalFormatter uses the same time styles that the basic date formatter does. Here are examples of each style:

formatter . timeStyle = . none formatter . string ( from : currentDate , to : twoMinutesAgo ) formatter . timeStyle = . short formatter . string ( from : currentDate , to : twoMinutesAgo ) // 11:00-11:02 AM formatter . timeStyle = . medium formatter . string ( from : currentDate , to : twoMinutesAgo ) // 11:00:00 AM-11:02:00 AM formatter . timeStyle = . long formatter . string ( from : currentDate , to : twoMinutesAgo ) // 11:00:00 AM GMT+2-11:02:00 AM GMT+2 formatter . timeStyle = . full formatter . string ( from : currentDate , to : twoMinutesAgo ) // 11:00:00 AM Central European Summer Time-11:02:00 AM Central European Summer Time





Note: RelativeDateTimeFormatter requires Xcode 11 and the latest beta versions of macOS 10.15 or iOS 13, which are currently in beta, as it is not available on previous versions.

RelativeDateTimeFormatter is a new date formatter from WWDC19 that formats relative dates as the amount of time between two dates or according to the current date and time.

To use it, create a formatter and generate a string from two dates.

RelativeDateTimeFormatter supports different date/time and unit styles, which we’ll go through later on.

let formatter = RelativeDateTimeFormatter () formatter . dateTimeStyle = . named formatter . unitsStyle = . full let currentDate = Date () formatter . localizedString ( for : currentDate , relativeTo : currentDate ) // now let yesterday = Calendar . current . date ( byAdding : . day , value : - 1 , to : currentDate ) ?? currentDate formatter . localizedString ( for : yesterday , relativeTo : currentDate ) // yesterday let fiveDays = Calendar . current . date ( byAdding : . day , value : 5 , to : currentDate ) ?? currentDate formatter . localizedString ( for : fiveDays , relativeTo : currentDate ) // in 5 days

You can also use a instance of DateComponents , which will format it based on the current date.

let minusOneDay = DateComponents ( day : - 1 ) formatter . localizedString ( from : minusOneDay ) // yesterday let plusOneDay = DateComponents ( day : 1 ) formatter . localizedString ( from : plusOneDay ) // tomorrow

As a bonus, all the strings that are generated are already localized, so you don’t need to worry about localization.

RelativeDateTimeFormatter supports two different date/time styles, which can be used by setting them before generating the string.

formatter . dateTimeStyle = . numeric // .numeric or .named

Numeric

The .numeric style is the default style and always uses the literal definition of the date.

formatter . dateTimeStyle = . numeric formatter . localizedString ( for : currentDate , relativeTo : currentDate ) // in 0 seconds formatter . localizedString ( for : yesterday , relativeTo : currentDate ) // 1 day ago formatter . localizedString ( for : fiveDays , relativeTo : currentDate ) // in 5 days

Named

The .named style falls back to the numeric style, but when possible, uses relative names such as yesterday or tomorrow .

formatter . dateTimeStyle = . named formatter . localizedString ( for : currentDate , relativeTo : currentDate ) // now formatter . localizedString ( for : yesterday , relativeTo : currentDate ) // yesterday formatter . localizedString ( for : fiveDays , relativeTo : currentDate ) // in 5 days

RelativeDateTimeFormatter contains four different unit styles, which format the date in different ways.

formatter . unitsStyle = . full // .abbreviated, .short, .full or .spellOut

Abbreviated

The .abbreviated style is the shortest style and abbreviates as much as possible.

formatter . unitsStyle = . abbreviated let oneMonthAgo = Calendar . current . date ( byAdding : . month , value : 1 , to : currentDate ) ?? currentDate formatter . localizedString ( for : currentDate , relativeTo : oneMonthAgo ) // 1 mo. ago

Short

The .short style is identical to the abbreviated style in English, but might generate different strings in other languages.

formatter . unitsStyle = . short let oneMonthAgo = Calendar . current . date ( byAdding : . month , value : 1 , to : currentDate ) ?? currentDate formatter . localizedString ( for : currentDate , relativeTo : oneMonthAgo ) // 1 mo. ago

Full

The .full style is the default style and uses longer names, such as month instead of mo. .

formatter . unitsStyle = . full let oneMonthAgo = Calendar . current . date ( byAdding : . month , value : 1 , to : currentDate ) ?? currentDate formatter . localizedString ( for : currentDate , relativeTo : oneMonthAgo ) // 1 month ago

Spelled Out

The .spellOut style is the longest style and uses spelled out versions of everything.

formatter . unitsStyle = . spellOut let oneMonthAgo = Calendar . current . date ( byAdding : . month , value : 1 , to : currentDate ) ?? currentDate formatter . localizedString ( for : currentDate , relativeTo : oneMonthAgo ) // one month ago

Conclusion

In this guide, you learned about the different date formatters that are built into Apple’s platforms, and how to use them.

I hope this post was useful and taught you something new. If you have any questions or feedback, feel free to mention me on Twitter or email me: [email protected].

Thanks for reading 📆