How do you format numbers, currency and percentages correctly?
Predict first
What does this print?
1234.5.formatted(.currency(code: "JPY").locale(Locale(identifier: "en_US")))
- ¥1,235
- ¥1,234
- ¥1,234.50
Predict first
What does this print?
print(0.256.formatted(.percent.locale(Locale(identifier: "en_US"))))
- 26%
- 25.6%
- 0.256%
Mental model. A formatter is a local who knows how this country writes its numbers. You hand over the number and they write it properly.
Use FormatStyle (value.formatted(.number), .currency(code:), .percent) or NumberFormatter. Both follow the locale: the decimal and grouping separators, the currency symbol and its position, even the digits. 1234.5 is $1,234.50 in the US and 1.234,50 € in Germany. A hand-built "$\(x)" is wrong for most of the world.
Use an ISO currency code ("USD"), not a symbol, because the code decides the digits: Japanese yen has none. Rounding uses banker’s rounding (half to even), so 1234.5 yen shows as ¥1,234. Note that .percent multiplies by 100 and keeps fraction digits by default, so 0.256 prints 25.6%; set .precision to control it. For user-typed input, parse with the same locale.
Yen has no minor unit, so the value is rounded to a whole number, and ties go to the even neighbour: 1234.
The percent style multiplies by 100 and keeps the fraction digits unless you limit them.
Common traps
- Formatting money with
String(format: "%.2f"). No grouping, no symbol, and the wrong separator for the user. - Treating a stored amount as formatted text. Store the number and currency code; format only for display.
They might follow up with
- How do you parse a localised number? A
FormatStyleparse strategy, orNumberFormatter.number(from:)with the user’s locale. - Why cache a
NumberFormatter? It is a heavy mutable object.FormatStylevalues are cheap and need no cache.
Related questions
- 2.8.5 Why shouldn’t you use Double for money, and what do you use instead?
- 2.2.6 What is a Locale, and how is it different from the user’s language?
- 2.2.7 FormatStyle or DateFormatter: which do you reach for?
← When do you use Scanner, and how does it compare with Regex and split? Why shouldn’t you use Double for money, and what do you use instead? →