Currency NumberFormatter - omit fraction part when the number is integer - ios

I need a specific behaviour from my NumberFormatter used to output currency:
If the number is integer (0, 0.00) it should not show decimal separator (0 €)
Else (123.90, 12.1), it should show two digits after decimal separator (123.90 €, 12.10 €).
The way I create and use my formatter now is the following:
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencySymbol = "€"
formatter.alwaysShowsDecimalSeparator = false
let num = formatter.string(from: 123.9)!
If created like this, the formatter always shows decimal separator, despite the fact that I set this property to false.
How can I achieve this?

Currency numberStyle is always returning decimal point followed two digits. So if you want to achieve your goal, you should modify the output string by yourself.
Please check the example code:
let number1: Double = 123.908392857
let number2: Int = 123
let number3: Float = 123.00
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencySymbol = "€"
let num1 = formatter.string(from: NSNumber(value: number1))! // Output €123.91
let num2 = formatter.string(from: NSNumber(value: number2))! // Output €123.00
let num3 = formatter.string(from: NSNumber(value: number3))! // Output €123.00
print("\(num1) \(num2) \(num3)")
// This is trick
let newNum1 = trimString(string: num1) // Output €123.91
let newNum2 = trimString(string: num2) // Output €123
let newNum3 = trimString(string: num3) // Output €123
print("\(newNum1) \(newNum2) \(newNum3)")
trimString is a simple trim function, you can put it in the String extension or any place you want.
func trimString(string: String) -> String {
if string.hasSuffix(".00") {
return String(string.dropLast(3))
}
else {
return string
}
}
You may have question about why alwaysShowsDecimalSeparator is not working then? It is for .decimal numberStyle and default decimalSeparator is "."

Related

Formatter issue when language changed in device

I'm trying to get float number from amount string with out currency symbol like "100.00". Its working properly in English language. When language changed to German in device, its behaviour is getting changed. How can I achieve float value with out affecting by language change in device.
func getFloatNumberFromString(_ str: String) -> Float {
guard let number = NumberFormatter().number(from: str) else {
return 0.0
}
return number.floatValue
}
another piece of below code to deal with it:
func removeFormatAmount() -> Double {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter.number(from: self) as! Double? ?? 0
}
When I use second method then the output is coming as 0.
Please let me know what am I missing or suggest me to deal with it.
Thanks in advance
In many European countries the decimal separator is a comma rather than a dot.
You could set the Locale of the formatter to a fixed value.
func float(from str: String) -> Float {
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
guard let number = formatter.number(from: str) else {
return 0.0
}
return number.floatValue
}
PS: I changed the signature to fit the Swift 3+ style
Did you try to cast directly? Like this.
let floatString = "12.34"
let number = Double(floatString) ?? 0.0

The NSFormatter for Converting English Number to persian or arabic Number in Swift 3

I read the similar questions here and Write this method in my app
let formatter = NumberFormatter()
func convertEngNumToPersianNum(num: String)->String{
let number = NSNumber(value: Int(num)!)
let format = NumberFormatter()
format.locale = Locale(identifier: "fa_IR")
let faNumber = format.string(from: number)
return faNumber!
}
I didn't get Error But I didn't get the result too!
my Number code is this :
let checkNumber = Home2ViewController().customtitle.count
personalCustom.text = ("\(checkNumber)")
I used another Number in another View Controller that works But I want to show this Number in persian or arabic number format not in English format
Try this :
func convertEngNumToPersianNum(num: String)->String{
//let number = NSNumber(value: Int(num)!)
let format = NumberFormatter()
format.locale = Locale(identifier: "fa_IR")
let number = format.number(from: num)
let faNumber = format.string(from: number!)
return faNumber!
}
OR repalce with your line
let number = format.number(from: num)
let faNumber = format.string(from: number!)
You can do something like,
let formatter = NumberFormatter()
formatter.locale = NSLocale.current // you can specify locale that you want
formatter.numberStyle = .decimal
formatter.usesGroupingSeparator = true
let number = formatter.number(from: "١٠.٠٠")
print(number ?? "")
To convert to Arabic while keeping the leading zeros
func convertToArDigits(_ digits: String) -> String {
// We need a CFMutableString and a CFRange:
let cfstr = NSMutableString(string: digits) as CFMutableString
var range = CFRange(location: 0, length: CFStringGetLength(cfstr))
// Do the transliteration (this mutates `cfstr`):
CFStringTransform(cfstr, &range, kCFStringTransformLatinArabic, false)
// Convert result back to a Swift string:
return (cfstr as String)
}
extension String {
public var faToEnDigits : String {
let farsiNumbers = ["٠": "0","١": "1","٢": "2","٣": "3","٤": "4","٥": "5","٦": "6","٧": "7","٨": "8","٩": "9"]
var txt = self
farsiNumbers.map { txt = txt.replacingOccurrences(of: $0, with: $1)}
return txt
}
public var enToFaDigits : String {
let englishNumbers = ["0": "۰","1": "۱","2": "۲","3": "۳","4": "۴","5": "۵","6": "۶","7": "۷","8": "۸","9": "۹"]
var txt = self
englishNumbers.map { txt = txt.replacingOccurrences(of: $0, with: $1)}
return txt
}
}

How to format a Double into Currency - Swift 3

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)"
}
}
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)"
}
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
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"
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
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)
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 €
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).
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!))!
}
}
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!
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?
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)
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.

How to format a string will trailing zeroes (SWIFT)

I have a text return value of "3.5".
I would need to format it to show "3.50"..
How do I do this?
It is all in strings as the value is extracted from a textfield
thanks
You can just print with a String initializer
if let value = Double(stringValue) {
print("I want two precision point for \(value) to be \(String(format: "%.2f", value))")
}
It will output to I want two precision point for 3.5 to be 3.50\n
You can use the 'NSNumberFormatter' to format the amount values as given below:
let currencyFormatter: NSNumberFormatter = {
let currencyFormatter = NSNumberFormatter()
currencyFormatter.locale = NSLocale(localeIdentifier: "en")
currencyFormatter.numberStyle = .CurrencyStyle
return currencyFormatter
}()
func formattedStringForAmount(amount: String) -> String {
return currencyFormatter.stringFromNumber(Double(amount)!)!
}

Convert Double to Scientific Notation in swift

I am trying to convert a given double into scientific notation, and running into some problems. I cant seem to find much documentation on how to do it either. Currently I am using:
var val = 500
var numberFormatter = NSNumberFormatter()
numberFormatter.numberStyle = NSNumberFormatterStyle.ScientificStyle
let number = numberFormatter.numberFromString("\(val)")
println(number as Double?)
// Prints optional(500) instead of optional(5e+2)
What am I doing wrong?
You can set NumberFormatter properties positiveFormat and exponent Symbol to format your string as you want as follow:
let val = 500
let formatter = NumberFormatter()
formatter.numberStyle = .scientific
formatter.positiveFormat = "0.###E+0"
formatter.exponentSymbol = "e"
if let scientificFormatted = formatter.string(for: val) {
print(scientificFormatted) // "5e+2"
}
update: Xcode 9 • Swift 4
You can also create an extension to get a scientific formatted description from Numeric types as follow:
extension Formatter {
static let scientific: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .scientific
formatter.positiveFormat = "0.###E+0"
formatter.exponentSymbol = "e"
return formatter
}()
}
extension Numeric {
var scientificFormatted: String {
return Formatter.scientific.string(for: self) ?? ""
}
}
print(500.scientificFormatted) // "5e+2"
The issue is that you are printing the number... not the formatted number. You are calling numberForString instead of stringForNumber
var val = 500
var numberFormatter = NSNumberFormatter()
numberFormatter.numberStyle = NSNumberFormatterStyle.ScientificStyle
let numberString = numberFormatter.stringFromNumber(val)
println(numberString)
Slight modification to the answer by leo-dabus to Xcode 9 Swift 4:
extension Double {
struct Number {
static var formatter = NumberFormatter()
}
var scientificStyle: String {
Number.formatter.numberStyle = .scientific
Number.formatter.positiveFormat = "0.###E+0"
Number.formatter.exponentSymbol = "e"
let number = NSNumber(value: self)
return Number.formatter.string(from :number) ?? description
}
}

Resources