
Swift Formatstyle
Format numbers, dates, currency, durations, and names for on-screen display using Swift FormatStyle instead of legacy Formatter classes.
Overview
swift-formatstyle is an agent skill for the Build phase that formats and parses display values on iOS using the FormatStyle protocol and Foundation format styles.
Install
npx skills add https://github.com/dpearson2699/swift-ios-skills --skill swift-formatstyleWhat is this skill?
- Maps FormatStyle and ParseableFormatStyle for integers, decimals, currency, percentages, and measurements
- Covers dates, date ranges, relative dates, Duration.TimeFormatStyle, and Duration.UnitsFormatStyle (iOS 16+)
- Includes PersonNameComponents, ByteCountFormatStyle, ListFormatStyle, and URL.FormatStyle
- Replaces Formatter subclasses with composable, cacheable format styles
- Recommends locale previews for en_US, de_DE, ar_SA, and ja_JP before shipping formatted UI
- FormatStyle available iOS 15+; Duration format styles require iOS 16+
Adoption & trust: 676 installs on skills.sh; 713 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You need consistent, locale-aware display and parsing for numbers and dates but still rely on brittle Formatter subclasses or manual string building.
Who is it for?
Solo iOS developers standardizing formatted labels and text fields in Swift 5 apps targeting iOS 15+.
Skip if: Projects that only need full app localization, String Catalog copy, or RTL layout overhauls without formatter API work—route those to ios-localization.
When should I use this skill?
Formatting numbers, currencies, dates, durations, measurements, names, byte counts, lists, or URLs for display; creating custom FormatStyle types; or replacing Formatter subclasses.
What do I get? / Deliverables
Views and models use typed FormatStyle instances for display and optional ParseableFormatStyle for input, ready for locale QA on representative regions.
- FormatStyle or ParseableFormatStyle usage in view or model layer
- Locale preview notes for representative regions
Recommended Skills
Journey fit
User-visible formatted strings are implemented in the iOS UI layer during Build, before polish and ship checks. FormatStyle applies directly to SwiftUI and UIKit presentation code on the frontend subphase of mobile apps.
How it compares
Skill reference for Apple FormatStyle APIs, not a general SwiftUI layout or App Store localization checklist.
Common Questions / FAQ
Who is swift-formatstyle for?
Indie iOS builders and agent users who want type-safe, reusable formatters for UI strings without maintaining custom Formatter subclasses.
When should I use swift-formatstyle?
During Build when implementing currency, dates, durations, lists, URLs, or byte counts in SwiftUI/UIKit, or when replacing legacy Formatter code.
Is swift-formatstyle safe to install?
Check the Security Audits panel on this Prism page and read the skill source; it is documentation-only with no declared runtime permissions.
SKILL.md
READMESKILL.md - Swift Formatstyle
# 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. For user-facing formatted output, always recommend previewing or testing 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](https://sosumi.ai/documentation/foundation/formatstyle) ## Contents - [Quick Reference](#quick-reference) - [Numbers](#numbers) - [Currency](#currency) - [Percentages](#percentages) - [Dates](#dates) - [Durations](#durations) - [Measurements](#measurements) - [Person Names](#person-names) - [Lists](#lists) - [Byte Counts](#byte-counts) - [URLs](#urls) - [SwiftUI Integration](#swiftui-integration) - [Custom FormatStyle](#custom-formatstyle) - [Common Mistakes](#common-mistakes) - [Review Checklist](#review-checklist) ## Quick Reference | Type | Style Access | Example | |------|-------------|---------| | `Int`, `Double` | `.number` | `42.formatted(.number.precision(.fractionLength(2)))` → `"42.00"` | | Currency | `.currency(code:)` | `29.99.formatted(.currency(code: "USD"))` → `"$29.99"` | | Percent | `.percent` | `0.85.formatted(.percent)` → `"85%"` | | `Date` | `.dateTime` | `Date.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` | `.url` | `url.formatted(.url.scheme(.never).host().path())` | ## Numbers ```swift // 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))