According to the documentation, [NSDecimalNumber decimalNumberWithString:] should use the locale decimal separator:
Whether the NSDecimalSeparator is a period (as is used, for example,
in the United States) or a comma (as is used, for example, in France)
depends on the default locale.
But when I try it, this code:
NSLog(#"%#", [NSDecimalNumber decimalNumberWithString:#"100,1"]);
NSLog(#"%#", [NSDecimalNumber decimalNumberWithString:#"100,1" locale:NSLocale.currentLocale]);
Gives...
100
100.1
...as output on both iOS 5 and iOS 6. I've tried with Swedish and French as regional settings as both these countries use comma (,) as decimal separator.
Shouldn't the output be the same?
(I know I can use [NSDecimalNumber decimalNumberWithString:locale:] to force the behavior, so this question is not about finding an alternative, just if this is a bug or I'm doing something wrong)
NSDecimalNumber is simply a storage class for number-type data. It's running a parser (NSNumberFormatter) on the string you pass it to create its number. The reason your second log statement works "better" is because the first one is using the default number format locale (it looks like it's en_US, but I can't verify this, see the edit blow for more information.) to parse, and "100,1" isn't a valid number so the "non-number" part gets stripped off. By specifying a locale that uses "," decimal separators it's capturing the full number properly.
When you NSLog() an NSDecimalNumber it's simply calling -description, which has no locale context and can print, more or less, whatever it wants.
If you want to print properly formatted numbers use NSNumberFormatter like so:
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:#"100.1"];
NSLog(#"%#", number);
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"fr_FR"];
[formatter setLocale:locale];
NSLog(#"%#", [formatter stringFromNumber:number]);
Or, briefly
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:#"100.1"];
NSLog(#"%#", [NSNumberFormatter localizedStringFromNumber:number numberStyle:NSNumberFormatterDecimalStyle]);
if you just want to use the current locale.
In summary:
NSDecimalNumber is just storage. Logging it does not reflect anything about locale.
In order to get NSDecimalNumber to store a number properly, its locale needs to match the locale of the expected input (-[NSLocale currentLocale] is a good choice here).
In order to display numbers formatted correctly for a given locale, use NSNumberFormatter.
Edit:
Ok, I've done some more research on this.
In GNUStep it looks like it ends up using the value for NSDecimalSeparator in NSUserDefaults (from a quick browse of their code).
Doing some experimentation I've found that none of the following affect the default parsing behavior, as far as I can tell:
NSDecimalSeparator in NSUserDefaults.
AppleLocale in NSUserDefaults.
NSLocaleCode in NSUserDefaults.
The value set for CFBundleDevelopmentRegion.
The Environment's LANG/LC_ALL/etc... values.
+[NSLocale systemLocale].
And obviously it is not +[NSLocale currentLocale], as this question stems from the fact that the current locale has no effect.
Related
Im making a calculator app and I am using a double for the precision. I didn't want the extra zeros and the decimal to be displayed so I changed the place holder token to "%.f". Because I did this if I do a problem on the calculator that does involve decimals they don't show up.
My question is basically if there is any way to have the %.f be used only when its necessary. If there is no way, what do you recommend doing to make it so I only have a decimal when its actually needed. Thanks.
You probably want to use NSDecimarlNumber, but to answer your question, you can user NSNumberFormatter to format the output for a double.
double someNumber = 1.9;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSLog(#"%#",[formatter stringFromNumber:[NSNumber numberWithDouble:someNumber]]);
My output
2014-01-13 11:30:41.429 DTMTestApp[23933:907] 1.9
For a calculator consider using NSDecimalNumber combined with NSNumberFormatter. There are going to be lot's of problems using floating point. Consider: (2 / 3.000000001) * 3.000000001, the result will not necessarily be exactly 2.
If I were to have EUR, or USD (both ISO currency codes), how could I make my NSNumberFormatter to properly format me a string like this?
For EUR code: 10.000,00 €
For USD code: $10,000.00
I could do this by setting localeIdentifier. But I really need to get it from the ISO currency code. Is this possible?
[numberFormatter stringFromNumber: [_property price]];
Thank you!
Use the setCurrencyCode: method of NSNumberFormatter.
[numberFormatter setCurrencyCode:#"EUR"];
or
[numberFormatter setCurrencyCode:#"USD"];
Keep in mind that even though the desired currency symbol will be used, the resulting currency value string is still going to be formatted based on the user's locale.
I have UILabel in which i want to show $ also it works fine but problem is that it works on simulator correct but when i test this code on device instead $ it shows Rs (Rupess) any idea how to fix this issue.
NSNumber *number=[[NSNumber alloc]initWithInt:1000];
NSString *No = [NSNumberFormatter localizedStringFromNumber:number numberStyle:NSNumberFormatterCurrencyStyle];
NSLog(#"%#", No);
UILabel * text=[NSString stringWithFormat:#"%#",No];
NSLog(#"%#",text);
Because by default the formatter will use the locale specified on the device it is being run on. If you want to force a particular display you need to use setLocale: and supply the appropriate NSLocale instance.
There's no issue.
As you are using localizedStringFromNumber and NSNumberFormatterCurrencyStyle to format number it's giving you the number format as per your region.
If you go to your simulator Setting - General - International - Region Format. It must be United State. Hence it shows $ when you run it on simulator.
If you check the same thing in your device. It'll show Region Format as India. Hence, it's showing Rs. sign.
If you want to see the $ sign just go ahead and change the setting in Device.
I doubt you want to set the result of [NSString stringWithFormat:#"%#",No] to a UILabel instance.
The other answers seem the most likely, choosing the correct device regional settings and using your existing code to output the value in the local format.
However if anyone is interested in outputting a number with an arbitrary currency format:
NSNumber *number = [NSNumber numberWithInt:1000];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[formatter setCurrencyCode:#"INR"];
NSString *text = [formatter stringFromNumber:number];
NSLog(#"%#", text);
// Release formatter as required
Though why you'd do this instead of just using the currency symbol and a basic string I'm not sure :p
NSString *text = #"₹1,000.00";
you got this issue because in device setting->general->international->reion format -> is INDIA
just change it to the country of your choice like if you want $ symbol then select USA
I'm wondering if there is any official way to put a currency symbol to the left or to the right from the money amount, depending of the region and the currency itself?
For example, if it's a $ sign, it should be to the left of the amount, as $20. If it's, for instance, € sign, then it should go as 20€.
I've found a simple way, I just check with If statement if the currency symbol is $ and append it to the left or to the right to my NSString. But this looks a bit lame like a crutch method.
I was unable to find some more convenient way. Is there any?
Thank you.
Apples official way ......
You need to use NSNumbers and NSNumberFormatter to convert the value to a currency and return a string representing it. This can be used in our labels e.t.c. someDouble refers to the number you wish to convert to a currency format.
NSNumber *currencyValue = [NSNumber numberWithDouble:someDouble];
NSNumberFormatter *formater = [[NSNumberFormatter alloc] init];
[formater setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *currencyString = [formater stringFromNumber:currencyValue];
NOTE: you may need to play around with the setLocale to get it to display the correct currency for a given region.
I am facing a strange problem. My app relies on a double conversion:
currency string -> number -> currency string
Basically, the single conversions are realized through the built-in localization functions of iOS. I recently found that the app does not work properly when the user uses CHF as currency. Apparently the default for this locale is to round all currency values to the nearest 5 cents. (eg. CHF 1.28 will become CHF 1.30, and 1.21 CHF will become CHF 1.20).
For a bunch of reasons it's easier for me to solve the formatting convention than solve the bug for that only locale.
Do you know a way to force the conversion to use a more detailed rounding approach (eg. 0.01 instead of 0.05) for every locale?
Thank you!
I found an interesting solution:
currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setGeneratesDecimalNumbers:YES];
[currencyFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
// This will force the rounding behavior:
[currencyFormatter setRoundingIncrement:[NSNumber numberWithFloat:0.01]];