How do you format numbers, currency and percentages correctly?

2.8.4 · L2 · Interview

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 FormatStyle parse strategy, or NumberFormatter.number(from:) with the user’s locale.
  • Why cache a NumberFormatter? It is a heavy mutable object. FormatStyle values 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? →