Format Styles In Excruciating Detail
Swift’s FormatStyle
and ParseableFormatStyle
are the easiest way to convert Foundation data types to and from localized strings. Unfortunately Apple hasn’t done a great job in documenting just what it can do, or how to use them.
This site is going to help you do just that.
Need a version of the site with more cussing in the title? Go to f*ckingformatstyle.com
You can start off by reading The Basics.
If you have a specific need and aren’t quite sure how to execute it, follow along:
Xcode 13+
This badge represents a style that is available on any platform that is built by Xcode 13 and above (iOS 15.0+, iPadOS 15.0+, Mac Catalyst 15.0+, tvOS 15.0+, watchOS 8.0+, macOS 12.0+):
- Number styles (including currency and percent styles)
- Date styles (including iso8601, relative, and verbatim styles)
- Date range styles (interval, and components)
- Measurement styles
- List styles
- Person name styles
- Byte count styles
Xcode 14+
This badge represents a style that has been updated, or is only available only, on platforms built by Xcode 14 and above (iOS 16.0+, iPadOS 16.0+, Mac Catalyst 16.0+, tvOS 16.0+, watchOS 9.0+, macOS 13.0+):
- (Updated) Byte count style
- (Updated) Measurement style
- Duration style
- URL style
- (Updated) Verbatim date style
You can access this new system in a few ways:
- Call
.formatted()
on a data type for a sensible, localized default - Call
.formatted(_: FormatStyle)
on a data type, and pass in a pre-defined or custom FormatStyle to customize your output - Call
.format()
on an instance of a FormatStyle
At its most basic, calling .formatted()
will give you a sensible default that uses your device’s current locale and calendar to display the value.
// Dates
Date(timeIntervalSinceReferenceDate: 0).formatted() // "12/31/2000, 5:00 PM"
// Measurements
Measurement(value: 20, unit: UnitDuration.minutes).formatted() // "20 min"
Measurement(value: 300, unit: UnitLength.miles).formatted() // "300 mi"
Measurement(value: 10, unit: UnitMass.kilograms).formatted() // "22 lb"
Measurement(value: 100, unit: UnitTemperature.celsius).formatted() // "212°F"
// Numbers
32.formatted() // "32"
Decimal(20.0).formatted() // "20"
Float(10.0).formatted() // "10"
Int(2).formatted() // "2"
Double(100.0003).formatted() // "100.0003"
// Names
PersonNameComponents(givenName: "Johnny", familyName: "Appleseed").formatted() // "Johnny Appleseed"
// Lists
["Alba", "Bruce", "Carol", "Billson"].formatted() // "Alba, Bruce, Carol, and Billson"
// TimeInterval
let referenceDay = Date(timeIntervalSinceReferenceDate: 0)
(referenceDay ..< referenceDay.addingTimeInterval(200)).formatted() // "12/31/00, 5:00 – 5:03 PM"
// Calling format on a style
let byteCountStyle = ByteCountFormatStyle(
style: .file,
allowedUnits: .all,
spellsOutZero: true,
includesActualByteCount: true,
locale: Locale.current
)
byteCountStyle.format(1_000_000_000) //"1 GB (1,000,000,000 bytes)"
In general, these are useful to quickly convert your values into strings.