When we convert like String.Format("{0:C}", 126.45) it returns $126.45
but if we convert like String.Format("{0:C}", -126.45) it returns ($126.45)
Why negative conversion return braces?
What to do if we don't want this braces?
Why don't you try something like:
String.Format("{0:$#,##0.00}", -126.45)
According to the documentation here a format of "{0:C1}" or "{0:C2}" should work, but for some strange reason it is not..
Another approach could be setting the CultureInfo:
CultureInfo culture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
culture.NumberFormat.CurrencyNegativePattern = 1;
string s = string.Format(culture, "{0:c}", -126.45);
Reference here
Swift 5 Here is best solution if you get after formate this kind of value (-300)
extension Double {
static let twoFractionDigits: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
formatter.currencySymbol = "$"
formatter.currencyCode = "USD"
formatter.numberStyle = .currency
formatter.usesGroupingSeparator = true
return formatter
}()
var formatted: String {
return Double.twoFractionDigits.string(for: self) ?? ""
}
}
In the en-US locale, parentheses are used to denote negative values. Visually scanning a long column of numbers, many people find it easier to see the negatives. Often it's the negative values that are of most concern (oops! my checking account balance is overdrawn).
To get different formatting behavior, you can change your locale, or you can change your format specifier to something like F.
It does parentheses, because that's the standard on whatever CultureInfo you are using.
Never done it myself but the make up of the format is controlled by the current NumberFormatInfo instance.
If you figure it out, answer your own question, and I'll plus you
Related
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 2 years ago.
I've developed a custom control for money input, which contains UITextField and UILabel. When the user taps on it, it becomes active and switches to the UITextField for data input and accepts only numbers and dot symbol, when the user finishes editing it becomes passive and switches to UILabel just to show formatted money value. But there is one little issue which I'm unable to fix a lot of days already.
Let's say the user writes down 88.99 and presses done, this becomes "$ 88.99" in a UILabel, next when the user again taps on it to edit the initial value I get the following value "88.98999999999999". To not present the entire code I selected the core part in a playground format which gives the same result as in my complete project:
extension NumberFormatter {
static public func defaultCurrencyFormatter() -> NumberFormatter {
let formatter = NumberFormatter()
formatter.usesGroupingSeparator = true
formatter.numberStyle = .currency
formatter.currencySymbol = ""
formatter.minimumFractionDigits = 1
formatter.maximumFractionDigits = 2
formatter.currencyGroupingSeparator = ","
formatter.currencyDecimalSeparator = "."
return formatter
}
}
let stringValue = NumberFormatter.defaultCurrencyFormatter().number(from: "88.99")?.stringValue
print(stringValue) // result is Optional("88.98999999999999")
I have no idea why using this NumberFormatter I get such a result. I was thinking that explicitly setting minimumFractionDigits and maximumFractionDigits will solve my issue but it does not affect my result
NumberFormatter is legacy from objc and it operates with NSNumber/CGFloat etc. and usually it is helpful for localized text formatting. Much powerful and convenient parser for numbers is Scanner but if you don't have complex data structure to parse and don't want to deal with Floating-point error mitigation just use swift's Float:
// Float from string
if let float = Float("88.99") {
print(float)
// String from float
let text = String(float)
print(text)
}
Prints:
88.99
88.99
Try this:
extension String {
var currencyStyle: String? {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 1
formatter.maximumFractionDigits = 2
formatter.usesGroupingSeparator = true
formatter.groupingSize = 3
formatter.currencyGroupingSeparator = ","
formatter.currencyDecimalSeparator = "."
if let double = Double(self) {
let number = NSNumber(value: double)
return formatter.string(from: number)
}
return nil
}
}
to use it:
let str = "12388.98999999999999".currencyStyle
print(str) // Optional("12,388.99")
I'm using NumberFormatter to format and validate user's currency input.
Since some people are using , and the others . irrespective of the selected locale, I'd like to have both of those symbols treated as the decimal separator when processing an input (i.e. formatting a String to Number).
How can I achieve this?
My current NumberFormatter configuration is as follows:
private lazy var currencyFormatter: NumberFormatter = {
let currencyFormatter = NumberFormatter()
currencyFormatter.numberStyle = .currency
currencyFormatter.locale = Locale.autoupdatingCurrent
currencyFormatter.currencySymbol = ""
currencyFormatter.maximumFractionDigits = 2
currencyFormatter.minimumFractionDigits = 2
return currencyFormatter
}()
Should I use multiple formatters to achieve the result I want?
The result
I'd like to have numbers 5,34 and 5.34 to be treated as valid and converted to the appropriate NSNumber. However, I'd like to still be able to reject 5.34lksdfns as invalid.
I'm trying to convert a textfield's text, which can be only numbers because of decimal number pad keyboard.
The variable I'm working with:
static var selectedMoneyMissing: Double = 30.0
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.roundingMode = .down
let roundedReplacing = formatter.string(from: NSNumber(value: Double(textField.text!.replacingOccurrences(of: ",", with: "."))!))
let roundedReplacingSecond = roundedReplacing.replacingOccurrences(of: " ", with: "")
print(roundedReplacing)
print(roundedReplacingSecond)
FiltersViewController.selectedMoneyMissing = Double(roundedReplacingSecond)!
I'm getting "unexpectedly found nil...." error:
This error occurs only when I'm putting value >= 1000. So I thought it could be because of the whitespace which is the reason why the roundedReplacingSecond variable exists. But it still does not work (actually, I don't know why the console is printing the variable "roundedReplacingSecond" with whitespace?).
You should configure your NumberFormatter more restrictive, especially by forbidding the use of a grouping and thousand separator:
formatter.groupingSeparator = false
formatter.hasThousandSeparator = false
See the documentation for even more properties. Then it shouldn't be necessary to do the text replacements at all, which may break depending on the users locale.
I'm trying to format a number as a currency.
let formatter = NSNumberFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_GB")
formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
let limit = formatter.numberFromString("12.99") as? NSDecimalNumber
However, the constant limit is returned a nil. The weird thing is that this piece of code was working up until recently but not sure what may have changed. Does the example look okay or am I missing something?
EDIT
To give context, I am trying to parse a string number (from an input element) to a decimal number for storing as currency value. My error appears setting the number style, I was using .CurrencyStyle but should use .DecimalStyle.
As a first test I tried
println(formatter.stringFromNumber(12.99)) // prints "£12.99"
Then I tried
let limit = formatter.numberFromString("£12.99") as? NSDecimalNumber // gives nil
But
let limit = formatter.numberFromString("£12.99") // gives 12.99
Whereas
let limit = formatter.numberFromString("12.99") // gives nil
So the currency symbol is mandatory
I am getting values back from a web service that gives me back prices in a string format, this is put into a Dictionary, so I get prices back as "1.5000" for example, which is obviously 1.50 in currency. However for the life of me I cannot get anything to work in Swift to format this correctly. In most other languages you can do this in a couple of seconds, so I'm getting a bit frustrated with something that is so simple.
Here's my test code:
var testnumber = "1.5000"
let n = NSNumberFormatter()
n.numberStyle = NSNumberFormatterStyle.DecimalStyle
n.maximumFractionDigits = 2
n.minimumFractionDigits = 2
let returnNumber = n.numberFromString(testnumber)
println("Returned number is \(returnNumber)")
This prints out in debug "number is Optional(1.5)" not 1.50!
I have changed NSNumberFormatterStyle.DecimalStyle to NSNumberFormatterStyle.CurrencyStyle as I thought that may do it for me as the returned number is a currency anyway, but that gives me back in debug "Returned number is nil" - which is even more confusing to me!
I have tried using maximumIntegerDigits and minimumIntegerDigits, setting locales using n.locale = NSLocale.currentLocale(), setting formatWidth, setting paddingPosition and paddingCharacter but nothing helps, I either get nil back to 1.5.
All I ultimately need to do is convert a string to a float or a currency value, and ensure there are 2 decimal places, and I can't believe it's this hard to accomplish!
Any help would be very gratefully received.
You are printing a number not a string
Xcode 11.4 • Swift 5.2 or later
extension Formatter {
static let usCurrency: NumberFormatter = {
let formatter = NumberFormatter()
formatter.locale = .init(identifier: "en_US")
formatter.numberStyle = .currency
return formatter
}()
}
extension String {
var double: Double? { Double(self) }
var usCurrencyFormatted: String {
Formatter.usCurrency.string(for: double) ?? Formatter.usCurrency.string(for: 0) ?? ""
}
}
"1.1222".usCurrencyFormatted // "$1.12"
"2".usCurrencyFormatted // "$2.00"
The problem is about numberFromString returning an optional - so you have to unwrap before printing. Just to be safe, you can use optional binding:
if let returnNumber = n.numberFromString(testnumber) {
println("Returned number is \(returnNumber)")
}
otherwise if it's ok for the app to crash if the optional is nil (in some cases this is a wanted behavior if the optional is expected to always contain a non nil value) just use forced unwrapping:
let returnNumber = n.numberFromString(testnumber)!
println("Returned number is \(returnNumber)")
That fixes the unwanted "Optional(xx)" text. As for formatting a float/double number, there are probably several ways of doing it - the one I would use is c-like string formatting, available via NSString:
let formattedNumber = NSString(format: "%.2f", returnNumber)
println("Returned number is \(formattedNumber)")
Use String Format Specifiers as reference if you want to know more about format specifiers.
You could probably just use the NSNumberFormatter that you just created.
let returnNumber = n.stringFromNumber(n.numberFromString(testnumber))
returnNumber will now be of type String.
The following returns to 2 decimal places for me in playgrounds. May be of some help to you. Uses NSNumberFormatter and then unwraps the optional
let testnumber: String = "1.50000"
let numberFormatter = NSNumberFormatter()
let number = numberFormatter.numberFromString(testnumber)
if let final = number?.floatValue {
println("Returned number is " + String(format: "%.2f", final))
}