How to format a Double into Currency - Swift 3

IosSwiftFormattingCurrency

Ios Problem Overview


I'm new to Swift programming and I've been creating a simple tip calculator app in Xcode 8.2, I have my calculations set up within my IBAction below. But when I actually run my app and input an amount to calculate (such as 23.45), it comes up with more than 2 decimal places. How do I format it to .currency in this case?

@IBAction func calculateButtonTapped(_ sender: Any) {
    
    var tipPercentage: Double {
        
        if tipAmountSegmentedControl.selectedSegmentIndex == 0 {
            return 0.05
        } else if tipAmountSegmentedControl.selectedSegmentIndex == 1 {
            return 0.10
        } else {
            return 0.2
        }
    }
    
    let billAmount: Double? = Double(userInputTextField.text!)
    
    if let billAmount = billAmount {
        let tipAmount = billAmount * tipPercentage
        let totalBillAmount = billAmount + tipAmount
        
        tipAmountLabel.text = "Tip Amount: $\(tipAmount)"
        totalBillAmountLabel.text = "Total Bill Amount: $\(totalBillAmount)"
    }
}

Ios Solutions


Solution 1 - Ios

You can use this string initializer if you want to force the currency to $:

String(format: "Tip Amount: $%.02f", tipAmount)

If you want it to be fully dependent on the locale settings of the device, you should use a NumberFormatter. This will take into account the number of decimal places for the currency as well as positioning the currency symbol correctly. E.g. the double value 2.4 will return "2,40 €" for the es_ES locale and "¥ 2" for the jp_JP locale.

let formatter = NumberFormatter()
formatter.locale = Locale.current // Change this to another locale if you want to force a specific locale, otherwise this is redundant as the current locale is the default already
formatter.numberStyle = .currency
if let formattedTipAmount = formatter.string(from: tipAmount as NSNumber) {
    tipAmountLabel.text = "Tip Amount: \(formattedTipAmount)"
}

Solution 2 - Ios

How to do it in Swift 4:

let myDouble = 9999.99
let currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true
currencyFormatter.numberStyle = .currency
// localize to your grouping and decimal separator
currencyFormatter.locale = Locale.current

// We'll force unwrap with the !, if you've got defined data you may need more error checking

let priceString = currencyFormatter.string(from: NSNumber(value: myDouble))!
print(priceString) // Displays $9,999.99 in the US locale

Solution 3 - Ios

You can to convert like that: this func convert keep for you maximumFractionDigits whenever you want to do

static func df2so(_ price: Double) -> String{
        let numberFormatter = NumberFormatter()
        numberFormatter.groupingSeparator = ","
        numberFormatter.groupingSize = 3
        numberFormatter.usesGroupingSeparator = true
        numberFormatter.decimalSeparator = "."
        numberFormatter.numberStyle = .decimal
        numberFormatter.maximumFractionDigits = 2
        return numberFormatter.string(from: price as NSNumber)!
    } 

i create it in class Model then when you call , you can accecpt it another class , like this

 print("InitData: result convert string " + Model.df2so(1008977.72))
//InitData: result convert string "1,008,977.72"

Solution 4 - Ios

The best way to do this is to create an NSNumberFormatter. (NumberFormatter in Swift 3.) You can request currency and it will set up the string to follow the user's localization settings, which is useful.

As an alternative to using a NumberFormatter, If you want to force a US-formatted dollars and cents string you can format it this way:

let amount: Double = 123.45

let amountString = String(format: "$%.02f", amount)

Solution 5 - Ios

you can create an Extension for either string or Int, I would show an example with String

extension String{
     func toCurrencyFormat() -> String {
        if let intValue = Int(self){
           let numberFormatter = NumberFormatter()
           numberFormatter.locale = Locale(identifier: "ig_NG")/* Using Nigeria's Naira here or you can use Locale.current to get current locale, please change to your locale, link below to get all locale identifier.*/ 
           numberFormatter.numberStyle = NumberFormatter.Style.currency
           return numberFormatter.string(from: NSNumber(value: intValue)) ?? ""
      }
    return ""
  }
}

link to get all locale identifier

Solution 6 - Ios

In addition to the NumberFormatter or String(format:) discussed by others, you might want to consider using Decimal or NSDecimalNumber and control the rounding yourself, thereby avoid floating point issues. If you're doing a simple tip calculator, that probably isn't necessary. But if you're doing something like adding up the tips at the end of the day, if you don't round the numbers and/or do your math using decimal numbers, you can introduce errors.

So, go ahead and configure your formatter:

let formatter: NumberFormatter = {
    let _formatter = NumberFormatter()
    _formatter.numberStyle = .decimal
    _formatter.minimumFractionDigits = 2
    _formatter.maximumFractionDigits = 2
    _formatter.generatesDecimalNumbers = true
    return _formatter
}()

and then, use decimal numbers:

let string = "2.03"
let tipRate = Decimal(sign: .plus, exponent: -3, significand: 125) // 12.5%
guard let billAmount = formatter.number(from: string) as? Decimal else { return }
let tip = (billAmount * tipRate).rounded(2)

guard let output = formatter.string(from: tip as NSDecimalNumber) else { return }
print("\(output)")

Where

extension Decimal {

    /// Round `Decimal` number to certain number of decimal places.
    ///
    /// - Parameters:
    ///   - scale: How many decimal places.
    ///   - roundingMode: How should number be rounded. Defaults to `.plain`.
    /// - Returns: The new rounded number.
    
    func rounded(_ scale: Int, roundingMode: RoundingMode = .plain) -> Decimal {
        var value = self
        var result: Decimal = 0
        NSDecimalRound(&result, &value, scale, roundingMode)
        return result
    }
}

Obviously, you can replace all the above "2 decimal place" references with whatever number is appropriate for the currency you are using (or possibly use a variable for the number of decimal places).

Solution 7 - Ios

 extension String{
    func convertDoubleToCurrency() -> String{
        let amount1 = Double(self)
        let numberFormatter = NumberFormatter()
        numberFormatter.numberStyle = .currency
        numberFormatter.locale = Locale(identifier: "en_US")
        return numberFormatter.string(from: NSNumber(value: amount1!))!
    }
}

Solution 8 - Ios

As of Swift 5.5, you can do this with the help of .formatted:

import Foundation

let amount = 12345678.9
print(amount.formatted(.currency(code: "USD")))
// prints: $12,345,678.90

This should support most common currency code, such as "EUR", "GBP", or "CNY".

Similarly, you can append locale to .currency:

print(amount.formatted(
    .currency(code:"EUR").locale(Locale(identifier: "fr-FR"))
))
// prints: 12 345 678,90 €

Solution 9 - Ios

Here's an easy way I've been going about it.

extension String {
    func toCurrency(Amount: NSNumber) -> String {
        var currencyFormatter = NumberFormatter()
        currencyFormatter.usesGroupingSeparator = true
        currencyFormatter.numberStyle = .currency
        currencyFormatter.locale = Locale.current

        return currencyFormatter.string(from: Amount)!
    }
}

Being used as follows

let amountToCurrency = NSNumber(99.99)
String().toCurrency(Amount: amountToCurrency)

Solution 10 - Ios

extension Float {
    var localeCurrency: String {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.locale = .current
        return formatter.string(from: self as NSNumber)!
    }
}
    amount = 200.02
    print("Amount Saved Value ",String(format:"%.2f", amountSaving. localeCurrency))

For me Its return 0.00! Looks to me Extenstion Perfect when accessing it return 0.00! Why?

Solution 11 - Ios

In 2022 using Swift 5.5, I created extensions that convert Float or Double into a currency using your device's locale or the locale you pass as an argument. You can check it out here https://github.com/ahenqs/SwiftExtensions/blob/main/Currency.playground/Contents.swift

import UIKit

extension NSNumber {
    
    /// Converts an NSNumber into a formatted currency string, device's current Locale.
    var currency: String {
        return self.currency(for: Locale.current)
    }
    
    /// Converts an NSNumber into a formatted currency string, using Locale as a parameter.
    func currency(for locale: Locale) -> String {
        let numberFormatter = NumberFormatter()
        numberFormatter.usesGroupingSeparator = locale.groupingSeparator != nil
        numberFormatter.numberStyle = .currency
        numberFormatter.locale = locale
        
        return numberFormatter.string(from: self)!
    }
}

extension Double {
    
    /// Converts a Double into a formatted currency string, device's current Locale.
    var currency: String {
        return NSNumber(value: self).currency(for: Locale.current)
    }
    
    /// Converts a Double into a formatted currency string, using Locale as a parameter.
    func currency(for locale: Locale) -> String {
        return NSNumber(value: self).currency(for: locale)
    }
}

extension Float {
    
    /// Converts a Float into a formatted currency string, device's current Locale.
    var currency: String {
        return NSNumber(value: self).currency(for: Locale.current)
    }
    
    /// Converts a Float into a formatted currency string, using Locale as a parameter.
    func currency(for locale: Locale) -> String {
        return NSNumber(value: self).currency(for: locale)
    }
}

let amount = 3927.75 // Can be either Double or Float, since we have both extensions.
let usLocale = Locale(identifier: "en-US") // US
let brLocale = Locale(identifier: "pt-BR") // Brazil
let frLocale = Locale(identifier: "fr-FR") // France
print("\(Locale.current.identifier) -> " + amount.currency) // default current device's Locale.
print("\(usLocale.identifier) -> " + amount.currency(for: usLocale))
print("\(brLocale.identifier) -> " + amount.currency(for: brLocale))
print("\(frLocale.identifier) -> " + amount.currency(for: frLocale))

// will print something like this:
// en_US -> $3,927.75
// en-US -> $3,927.75
// pt-BR -> R$ 3.927,75
// fr-FR -> 3 927,75 €

I hope it helps, happy coding!

Solution 12 - Ios

Here's how:

    let currentLocale = Locale.current
    let currencySymbol = currentLocale.currencySymbol
    let outputString = "\(currencySymbol)\(String(format: "%.2f", totalBillAmount))"

1st line: You're getting the current locale

2nd line: You're getting the currencySymbol for that locale. ($, £, etc)

3rd line: Using the format initializer to truncate your Double to 2 decimal places.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGarView Question on Stackoverflow
Solution 1 - Iossilicon_valleyView Answer on Stackoverflow
Solution 2 - IosCamilo OrtegónView Answer on Stackoverflow
Solution 3 - IosChung NguyenView Answer on Stackoverflow
Solution 4 - IosDuncan CView Answer on Stackoverflow
Solution 5 - Iosknig_TView Answer on Stackoverflow
Solution 6 - IosRobView Answer on Stackoverflow
Solution 7 - IosMuhammad ZeeshanView Answer on Stackoverflow
Solution 8 - IosRanoiaetepView Answer on Stackoverflow
Solution 9 - IosOmarView Answer on Stackoverflow
Solution 10 - IosKkMIWView Answer on Stackoverflow
Solution 11 - IosAndré Henrique da SilvaView Answer on Stackoverflow
Solution 12 - IosAtharva VaidyaView Answer on Stackoverflow