Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
dpearson2699 avatar

Swift Formatstyle

  • 1.6k installs
  • 944 repo stars
  • Updated July 15, 2026
  • dpearson2699/swift-ios-skills

swift-formatstyle is an agent skill for format and parse numbers, currency, dates, and lists with swift formatstyle apis.

About

The swift-formatstyle skill is designed for format and parse numbers, currency, dates, and lists with Swift FormatStyle APIs. Swift FormatStyle Format values for human-readable display using the FormatStyle protocol and Foundation's concrete format styles. Replaces legacy Formatter subclasses with a type-safe, composable, cacheable API. Invoke when the user formats numbers, currency, dates, or measurements in SwiftUI or Foundation.

  • Quick Reference.
  • SwiftUI Integration.
  • Custom FormatStyle.
  • Common Mistakes.
  • Review Checklist.

Swift Formatstyle by the numbers

  • 1,596 all-time installs (skills.sh)
  • +104 installs in the week ending Jul 29, 2026 (Skillselion tracking)
  • Ranked #151 of 1,039 Mobile Development skills by installs in the Skillselion catalog
  • Security screen: LOW risk (skills.sh audit)
  • Data as of Jul 31, 2026 (Skillselion catalog sync)
At a glance

swift-formatstyle capabilities & compatibility

Capabilities
quick reference · swiftui integration · custom formatstyle · common mistakes
From the docs

What swift-formatstyle says it does

Format and parse values for display using the FormatStyle and ParseableFormatStyle protocols and Foundation's concrete styles. Use when formatting numbers (integers, floating-point
SKILL.md
Format and parse values for display using the FormatStyle and ParseableFormatStyle protocols and Foundation's concrete styles. Use when formatting numbers (inte
SKILL.md
npx skills add https://github.com/dpearson2699/swift-ios-skills --skill swift-formatstyle

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs1.6k
repo stars944
Security audit3 / 3 scanners passed
Last updatedJuly 15, 2026
Repositorydpearson2699/swift-ios-skills

How do I format and parse numbers, currency, dates, and lists with swift formatstyle apis?

Format and parse numbers, currency, dates, and lists with Swift FormatStyle APIs.

Who is it for?

iOS developers using Foundation FormatStyle and ParseableFormatStyle.

Skip if: Skip for UI layout tasks without formatting and parsing needs.

When should I use this skill?

User formats numbers, currency, dates, or measurements in SwiftUI or Foundation.

What you get

Completed swift-formatstyle workflow with documented commands, files, and expected deliverables.

  • FormatStyle Swift snippets
  • Localized display strings
  • Custom FormatStyle implementations

By the numbers

  • Documents 10+ concrete FormatStyle types including currency, duration, measurement, and ListFormatStyle
  • FormatStyle base availability starts at iOS 15+; Duration styles require iOS 16+

Files

SKILL.mdMarkdownGitHub ↗

Swift FormatStyle

Format values for human-readable display using the FormatStyle protocol and Foundation's concrete format styles. Replaces legacy Formatter subclasses with a type-safe, composable, cacheable API.

Locale-aware display is an i18n concern even when the app is not adding new languages. When reviewing user-facing FormatStyle output or SwiftUI Text(_:format:), always include an actionable preview/test step for the exact rendered UI in representative locales such as en_US, de_DE, ar_SA, and ja_JP; check separators, numbering systems, calendars, currency and unit conventions, text direction, and layout-sensitive output. Keep this skill focused on FormatStyle, ParseableFormatStyle, parsing, and reusable formatter API design; route broader localization work such as String Catalogs, bundles, plurals, localized copy, and RTL layout review to ios-localization. Do not use "not adding languages" as the reason to skip ios-localization; locale-sensitive formatting can be a localization review issue without translation work.

Docs: FormatStyle

Contents

Quick Reference

TypeStyle AccessExample
Int, Double.number42.formatted(.number.precision(.fractionLength(2)))"42.00"
Decimal.number, .percent, .currency(code:)Decimal(string: "0.1")!.formatted(.percent) -> "10%"
Currency.currency(code:)29.99.formatted(.currency(code: "USD")) -> "$29.99"
Percent.percent0.85.formatted(.percent)"85%"
Date.dateTimeDate.now.formatted(.dateTime.month().day().year())
Date range.interval(date1..<date2).formatted(.interval)
Relative date.relative(presentation:unitsStyle:)date.formatted(.relative(presentation: .named))"yesterday"
Duration.time(pattern:)Duration.seconds(3661).formatted(.time(pattern: .hourMinuteSecond))"1:01:01"
Duration.units(allowed:width:)Duration.seconds(90).formatted(.units(allowed: [.minutes, .seconds]))"1 min, 30 sec"
Measurement.measurement(width:)Measurement(value: 72, unit: UnitTemperature.fahrenheit).formatted(.measurement(width: .abbreviated))
PersonNameComponents.name(style:)name.formatted(.name(style: .short))"Tom"
[String].list(type:width:)["A","B","C"].formatted(.list(type: .and))"A, B, and C"
Byte count.byteCount(style:)Int64(1_048_576).formatted(.byteCount(style: .memory))"1 MB"
URL.urlurl.formatted(.url.scheme(.never).host().path())

Numbers

// Default locale-aware formatting
let n = 1234567.formatted()  // "1,234,567" (en_US)

// Precision
1234.5.formatted(.number.precision(.fractionLength(0...2)))  // "1,234.5"
1234.5.formatted(.number.precision(.significantDigits(3)))    // "1,230"

// Rounding
1234.formatted(.number.rounded(rule: .down, increment: 100)) // "1,200"

// Grouping
1234567.formatted(.number.grouping(.never))                   // "1234567"

// Notation
1_200_000.formatted(.number.notation(.compactName))           // "1.2M"
42.formatted(.number.notation(.scientific))                    // "4.2E1"

// Sign display
(-42).formatted(.number.sign(strategy: .always()))            // "+42" / "-42"

// Locale override
42.formatted(.number.locale(Locale(identifier: "de_DE")))     // "42"

Docs: IntegerFormatStyle, FloatingPointFormatStyle

Decimals

Use Decimal.FormatStyle for exact decimal values, especially money-like values that should not pass through binary floating-point.

let amount = Decimal(string: "12345.67")!

amount.formatted(.number)                         // "12,345.67" (en_US)
amount.formatted(.number.grouping(.never))        // "12345.67"
Decimal(string: "0.1")!.formatted(.percent)       // "10%"
amount.formatted(.currency(code: "USD"))          // "$12,345.67"

// Parsing with the same style
let price = try? Decimal("$3,500.63", format: .currency(code: "USD"))

Docs: Decimal.FormatStyle

Currency

29.99.formatted(.currency(code: "USD"))   // "$29.99"
29.99.formatted(.currency(code: "EUR"))   // "€29.99"
29.99.formatted(.currency(code: "JPY"))   // "¥30"

// Customize precision
let style = FloatingPointFormatStyle<Double>.Currency(code: "USD")
    .precision(.fractionLength(0))
1234.56.formatted(style)  // "$1,235"

Percentages

0.85.formatted(.percent)                                      // "85%"
0.8567.formatted(.percent.precision(.fractionLength(1)))       // "85.7%"
42.formatted(.percent)                                         // "42%"  (integer)

Dates

let now = Date.now

// Components
now.formatted(.dateTime.year().month().day())           // "Apr 22, 2026"
now.formatted(.dateTime.hour().minute())                // "4:30 PM"
now.formatted(.dateTime.weekday(.wide).month(.wide).day()) // "Wednesday, April 22"

// Predefined styles
now.formatted(date: .long, time: .shortened)            // "April 22, 2026 at 4:30 PM"
now.formatted(date: .abbreviated, time: .omitted)       // "Apr 22, 2026"

// ISO 8601
now.formatted(.iso8601)                                 // "2026-04-22T16:30:00Z"

// Relative
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: .now)!
yesterday.formatted(.relative(presentation: .named))    // "yesterday"
yesterday.formatted(.relative(presentation: .numeric))  // "1 day ago"

// Treat relative strings as standalone text; embedding them inside another
// sentence can be grammatically wrong in some locales. Recommend previewing or
// testing the exact screen in representative locales before approving copy.
Text(yesterday, format: .relative(presentation: .named))

// Interval
(date1..<date2).formatted(.interval.month().day().hour().minute())

// Components (countdown-style)
(date1..<date2).formatted(.components(style: .wide, fields: [.day, .hour]))
// "2 days, 5 hours"

Docs: Date.FormatStyle, Date.RelativeFormatStyle, Date.IntervalFormatStyle

Anchored Relative Dates (iOS 18+)

Date.AnchoredRelativeFormatStyle formats relative to a fixed anchor date rather than the current moment. It requires iOS 18+.

Docs: Date.AnchoredRelativeFormatStyle

Durations

Duration (iOS 16+) has two format styles:

Docs: Duration.TimeFormatStyle, Duration.UnitsFormatStyle

TimeFormatStyle — compact separator-based

let d = Duration.seconds(3661)

d.formatted(.time(pattern: .hourMinuteSecond))       // "1:01:01"
d.formatted(.time(pattern: .hourMinute))             // "1:01"
d.formatted(.time(pattern: .minuteSecond))           // "61:01"

// Fractional seconds
Duration.seconds(3.75).formatted(
    .time(pattern: .minuteSecond(padMinuteToLength: 2, fractionalSecondsLength: 2))
)  // "00:03.75"

UnitsFormatStyle — labeled units

Duration.seconds(3661).formatted(
    .units(allowed: [.hours, .minutes, .seconds], width: .abbreviated)
)  // "1 hr, 1 min, 1 sec"

Duration.seconds(90).formatted(
    .units(allowed: [.minutes, .seconds], width: .wide)
)  // "1 minute, 30 seconds"

Duration.seconds(90).formatted(
    .units(allowed: [.minutes, .seconds], width: .narrow)
)  // "1m 30s"

// Limit unit count
Duration.seconds(3661).formatted(
    .units(allowed: [.hours, .minutes, .seconds], width: .abbreviated, maximumUnitCount: 2)
)  // "1 hr, 1 min"

Measurements

let temp = Measurement(value: 72, unit: UnitTemperature.fahrenheit)
temp.formatted(.measurement(width: .wide))        // "72 degrees Fahrenheit"
temp.formatted(.measurement(width: .abbreviated))  // "72°F"
temp.formatted(.measurement(width: .narrow))       // "72°"

let dist = Measurement(value: 5, unit: UnitLength.kilometers)
dist.formatted(.measurement(width: .abbreviated, usage: .road))  // "3.1 mi" (en_US)

Docs: Measurement.FormatStyle

Person Names

var name = PersonNameComponents()
name.givenName = "Thomas"
name.familyName = "Clark"
name.middleName = "Louis"
name.namePrefix = "Dr."
name.nickname = "Tom"
name.nameSuffix = "Esq."

name.formatted(.name(style: .long))        // "Dr. Thomas Louis Clark Esq."
name.formatted(.name(style: .medium))      // "Thomas Clark"
name.formatted(.name(style: .short))       // "Tom"
name.formatted(.name(style: .abbreviated)) // "TC"

Style resolution follows priority: script → user preferences → locale → developer setting.

Docs: PersonNameComponents.FormatStyle

Lists

["Alice", "Bob", "Charlie"].formatted(.list(type: .and))
// "Alice, Bob, and Charlie"

["Alice", "Bob", "Charlie"].formatted(.list(type: .or))
// "Alice, Bob, or Charlie"

// With member formatting
[1, 2, 3].formatted(.list(memberStyle: .number, type: .and))
// "1, 2, and 3"

// Narrow width
["A", "B", "C"].formatted(.list(type: .and, width: .narrow))
// "A, B, C"

Docs: ListFormatStyle

Byte Counts

Int64(1_048_576).formatted(.byteCount(style: .memory))   // "1 MB"
Int64(1_048_576).formatted(.byteCount(style: .file))      // "1 MB"
Int64(1_048_576).formatted(.byteCount(style: .binary))    // "1 MiB"

Docs: ByteCountFormatStyle

URLs

URL.FormatStyle requires iOS 16+. The default style includes scheme, host, and path. Treat port, query, and fragment as opt-in display components; add .port(.always), .query(.always), or .fragment(.always) only when those components should be visible.

let url = URL(string: "https://www.example.com:8080/path?q=1#section")!
url.formatted()
// "https://www.example.com/path"

url.formatted(.url.scheme(.never).host().path())
// "www.example.com/path"

url.formatted(.url.scheme(.never).host().path().query(.always))
// "www.example.com/path?q=1"

url.formatted(.url.scheme(.never).host().path().fragment(.always))
// "www.example.com/path#section"

When auditing URL component choices, recommend previewing or testing the exact rendered URL text in representative locales, especially when choosing whether to show or hide scheme, path, query, port, or fragment.

Docs: URL.FormatStyle

SwiftUI Integration

Text accepts a format: parameter, keeping formatting out of the view model.

// Inline format style
Text(price, format: .currency(code: "USD"))
Text(date, format: .dateTime.month().day().year())
Text(duration, format: .units(allowed: [.minutes, .seconds]))

// Timer-style (live updating)
Text(.now, style: .timer)
Text(.now, style: .relative)
Text(timerInterval: start...end)

Prefer `Text(_:format:)` over string interpolation — it allows SwiftUI to re-render only the formatted value and supports accessibility scaling. For every SwiftUI formatted Text review, include a representative-locale preview, UI test, or snapshot test recommendation for the exact screen.

Custom FormatStyle

Conform to FormatStyle for domain-specific formatting. Conform to ParseableFormatStyle if you also need parsing. FormatStyle refines Decodable, Encodable, and Hashable, and Foundation caches identical customized style instances, so reusable value-style formatters are cheap.

struct AbbreviatedCountStyle: FormatStyle {
    func format(_ value: Int) -> String {
        switch value {
        case ..<1_000:
            return "\(value)"
        case 1_000..<1_000_000:
            return String(format: "%.1fK", Double(value) / 1_000)
        default:
            return String(format: "%.1fM", Double(value) / 1_000_000)
        }
    }
}

extension FormatStyle where Self == AbbreviatedCountStyle {
    static var abbreviatedCount: AbbreviatedCountStyle { .init() }
}

// Usage
let followers = 12_500
Text(followers, format: .abbreviatedCount)  // "12.5K"

For parseable custom styles, pair formatting with a parse strategy and use the same conventions in both directions. Prefer this only when users edit or import the formatted value; display-only styles should stay as FormatStyle.

Docs: ParseableFormatStyle

Common Mistakes

MistakeFix
Using legacy NumberFormatter / DateFormatter in new codeUse FormatStyle (iOS 15+). Foundation caches format style instances automatically.
String interpolation for formatted numbers in TextUse Text(value, format:) for locale correctness and accessibility
Hardcoding locale in format stylesOmit .locale() to inherit the user's current locale by default
Assuming URL.formatted() preserves query strings, ports, or fragmentsDefault URL formatting includes scheme, host, and path only; opt in with .query(.always), .port(.always), or .fragment(.always)
Embedding relative date output inside larger sentencesUse Date.RelativeFormatStyle output as standalone text; localized grammar may not fit interpolation
Forgetting availability checksURL.FormatStyle and Duration format styles require iOS 16+; Date.AnchoredRelativeFormatStyle requires iOS 18+
Using .time(pattern:) for labeled duration displayUse .units(allowed:width:) for "1 hr, 30 min" style output
Creating Formatter instances in body or tight loopsFormatStyle instances are value types cached by Foundation; safe to create inline
Formatting Duration with DateComponentsFormatterUse Duration.TimeFormatStyle or Duration.UnitsFormatStyle directly
Ignoring usage: parameter for measurementsSpecify .road, .asProvided, etc. for locale-aware unit conversion
Using binary floating-point for exact decimal display/parsingUse Decimal.FormatStyle and matching parse strategies for exact decimal values

Review Checklist

  • [ ] FormatStyle used instead of legacy Formatter subclasses for iOS 15+ targets
  • [ ] URL.FormatStyle and Duration styles gated to iOS 16+; anchored relative dates gated to iOS 18+
  • [ ] Text(_:format:) used instead of pre-formatting strings for SwiftUI text
  • [ ] Every user-facing formatted value or SwiftUI formatted Text includes an explicit representative-locale preview/test recommendation
  • [ ] No hardcoded locale unless explicitly needed (e.g., server communication)
  • [ ] Decimal values use Decimal.FormatStyle when exact decimal formatting or parsing matters
  • [ ] URL formatting explicitly includes query, port, or fragment only when those components should display, with representative-locale preview for user-facing URL text
  • [ ] Relative date strings are used standalone, not interpolated into larger localized sentences, and previewed in representative locales
  • [ ] Duration formatting uses Duration.TimeFormatStyle or Duration.UnitsFormatStyle
  • [ ] Currency codes are ISO 4217 strings, not hardcoded symbols
  • [ ] Measurement formatting includes usage: for user-facing display
  • [ ] Custom FormatStyle types conform to Codable + Hashable for caching

References

Related skills

How it compares

Pick swift-formatstyle over generic localization skills when migrating Swift UI code from Formatter subclasses to type-safe FormatStyle APIs.

FAQ

What does swift-formatstyle do?

Format and parse numbers, currency, dates, and lists with Swift FormatStyle APIs.

When should I use swift-formatstyle?

User formats numbers, currency, dates, or measurements in SwiftUI or Foundation.

Is swift-formatstyle safe to install?

Review the Security Audits panel on this page before installing in production.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.