How to get NSNumberFormatter currency style from ISOCurrencyCodes? - ios

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.

Related

Remove trailing zeros of a double only when necessary

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.

Best NSString format for displaying long decimal numbers?

What is the best NSString format for displaying long decimal numbers? I get undesirable rounding that occurs when I try something like:
[NSString stringWithFormat:#"%g", calcResult];
Ideally, I would like the format:
xxx,xxx.xxxxxxxxxxxxxx
with a limit on total number of places collectively between the whole and decimal numbers.
So for example, if that limit were 10 places, the following would be the desired format:
1,234.567891
or
1,234,567.891
Thanks in advance.
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
// This style turns on locale-specific thousands separators.
// US English uses commas.
formatter.numberStyle = NSNumberFormatterDecimalStyle;
// This specifies exactly 10 decimal digits of output.
formatter.usesSignificantDigits = YES;
formatter.minimumSignificantDigits = 10;
formatter.maximumSignificantDigits = 10;
NSLog(#"%#", [formatter stringFromNumber:#(1234.567891)]);
NSLog(#"%#", [formatter stringFromNumber:#(1234567.891)]);
Output:
2013-12-04 17:36:32.372 numberFormatter[70896:303] 1,234.567891
2013-12-04 17:36:32.373 numberFormatter[70896:303] 1,234,567.891
To convert a number value using grouping and decimal separator according to your desired locale you definitely need to use NSNumberFormatter.
On an instance of NSNumberFormatter you can set your desired rounding algorithm (number of digits, rounding behavior). Also it will automatically use current locale for you. You'll be left with a simple
[numberFormatter stringFromNumber:myNumber];
Note that you'll be able to use different formatters that have different rounding rules: 2/3 can be printed as 0.6, 0.7, 0.67 and so on. If your number is inherently decimal, like the numbers that occur in finance, you can consider using NSDecimalNumber to hold the number value. Once set, an instance of NSDecimalNumber will remember the exact number of decimal digits and if you print it with a generic NSNumberFormatter, you'll never lose significant digits.
This is how you can limit the total number of digits to 10:
Given a decimal number, divide or multiply it by 10 until it's between 0.1 and 1.
Round it to 10 digits after decimal point.
Reverse the procedure in 1.
Now you have a decimal number with exactly 10 significant digits.
Technically, you're able to convert NSDecimalNumber to a string without using an NSNumberFormatter by -descriptionWithLocale:. But I don't think it can do groupings.
And if your code isn't supposed to be internationalized, you can also do
[NSString stringWithFormat:#"%#", decimalNumber];

How to place a currency symbol prefix or postfix with a string?

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.

NSDecimalNumber decimalNumberWithString: ignores current locale

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.

Change default locale behavior for currency formatting

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]];

Resources