it seems like in iOS 13 it has changed the NSNumberFormatter way of displaying figures.
Previously in iOS 12, setting the region format to Colombia, for a figure of 12.00, it will be shown as 12 which is correct.
However now in iOS 13, it shows as 12,00 which is not correct as in Colombia it should not show the ,00 at the back of the 12.
Any idea what has changed in iOS 13 and how we can workaround for this?
Here's my code. Thanks!
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[formatter setCurrencySymbol:#""];
NSString *floatString = [NSString stringWithFormat:#"%.2f", floatValue];
NSDecimalNumber* number = [NSDecimalNumber decimalNumberWithString:floatString];
NSString *numberString = [formatter stringFromNumber:number];
NSLog(#"%#", numberString");
Update: After updating to iOS 13.2, this issue is gone.
In iOS 13.1 has a bug when you have a different decimal point instead of . to anything else.
For example: My locale is Poland. So if I have amountString = "4.5". Following code return always nil.
let currencyFormatter = NumberFormatter()
currencyFormatter.currencySymbol = ""
currencyFormatter.numberStyle = .currency
currencyFormatter.locale = Locale.current
if let finalNumber = currencyFormatter.number(from: amountString){
return finalNumber.doubleValue
}
return nil
Related
I have an issue with the textfield. This case works fine with the english language. However, if the device language is change to french (canada) , the textfield is not showing the values after the decimal.
For english:
I enter 99.99 and click Done. The text field display 99.99
For french:
I enter 99,99 and click Done . The text field display 99,00
Here is my code:
_amountField.text = [_amountField currencyFormatFromValue:[NSNumber numberWithDouble:_amountField.text.doubleValue]];
Here the [NSNumber numberWithDouble:_amountField.text.doubleValue] part is returning 99.99 in case of english and 99,00 in case of french
-(NSString *)currencyFormatFromValue:(NSNumber *)value{
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.positiveFormat = #"###.00";
formatter.roundingMode = NSNumberFormatterRoundFloor;
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *groupingSeparator = [[NSLocale currentLocale] objectForKey:NSLocaleGroupingSeparator];
[formatter setGroupingSeparator:groupingSeparator];
[formatter setUsesGroupingSeparator:YES];
[formatter setCurrencySymbol:#""];
[formatter setMinimumIntegerDigits:1];
NSString *formattedValue = [formatter stringFromNumber:value];
return formattedValue;
}
I am not sure, why the french text which is converted in double is terminating the decimal values. Any ideas?
Do I need to convert the text back to english before I sent the value to formatter?
I think your positiveFormat specification with the period is conflicting with NSNumberFormatterCurrencyStyle. I would try commenting out a bunch of lines and recompiling:
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
// formatter.positiveFormat = #"###.00";
// formatter.roundingMode = NSNumberFormatterRoundFloor;
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
// NSString *groupingSeparator = [[NSLocale currentLocale] objectForKey:NSLocaleGroupingSeparator];
// [formatter setGroupingSeparator:groupingSeparator];
// [formatter setUsesGroupingSeparator:YES];
// [formatter setCurrencySymbol:#""];
// [formatter setMinimumIntegerDigits:1];
NSString *formattedValue = [formatter stringFromNumber:value];
return formattedValue;
In my experience, the formatting out of the box will include grouping separator, currency symbols, rounding mode, etc. Specifying it again can potentially confuse the formatter.
If you really need to explicitly specify the positive format, you can try building the positive format string using the NSLocaleDecimalSeparator constant so that it will be a period or comma as required:
NSString *decimalSeparator = [[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator];
formatter.positiveFormat = [NSString stringWithFormat:#"###%#00", decimalSeparator];
But I don't recommend it!
I found a way to make it work. I need to remove the , character in case of french that occur in the text field and send to formatter .
_amountField.text = [_amountField currencyFormatFromValue:[NSNumber numberWithDouble:[_amountField.text strippedAmount]doubleValue]];
and
//macro
#define IsFrenchLanguage() ([[[NSLocale preferredLanguages] objectAtIndex:0] rangeOfString:#"fr"].location != NSNotFound)
-(NSString *) strippedAmountString
{
NSString * thousandsSeparator = IsFrenchLanguage() ? #" " : #",";
return [self.amountField.text stringByReplacingOccurrencesOfString:thousandsSeparator withString:#""];
}
Ok, so I am writing a calculator app now. So far, I'm not having much luck in regard to decimals (my most recent approach hasn't worked well).
-(void) DecimalAdded
{
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setAlwaysShowsDecimalSeparator:YES];
[formatter setGeneratesDecimalNumbers:YES];
[formatter setDecimalSeparator:#"."];
//first convert the float value of CN into NSnumber
NSNumber *nextstepNumFromCNF= [NSNumber numberWithFloat:currentNumber];
//now we have to convert that number into a string
NSString *CNconverted = [formatter stringFromNumber:nextstepNumFromCNF];
NSNumber *CNdecmAddedAndReadyForPars = [formatter numberFromString:CNconverted];
currentNumber = currentNumber*10 + [CNdecmAddedAndReadyForPars floatValue];
CalculatorScreen = [NSMutableString stringWithFormat: #"%#", CNconverted];
I can append the string to the Calculator screen I can say the number is 1, I see "1." as I'm typing. However this is usually converted to 1 during th float conversion (which is correct).
What is this best way to accomplish this?
I need to print a float value in area of limited width most efficiently. I'm using an NSNumberFormatter, and I set two numbers after the decimal point as the default, so that when I have a number like 234.25 it is printed as is: 234.25. But when I have 1234.25 I want it to be printed as: 1234.3, and 11234.25 should be printed 11234.
I need a maximum of two digits after the point, and a maximum of five digits overall if I have digits after the point, but it also should print more than five digits if the integer part has more.
I don't see ability to limit the total number of digits in NSNumberFormatter. Does this mean that I should write my own function to format numbers in this way? If so, then what is the correct way of getting the count of digits in the integer and fractional parts of a number? I would also prefer working with CGFLoat, rather than NSNumber to avoid extra type conversions.
You're looking for a combination of "maximum significant digits" and "maximum fraction digits", along with particular rounding behavior. NSNumberFormatter is equal to the task:
float twofortythreetwentyfive = 234.25;
float onetwothreefourtwentyfive = 1234.25;
float eleventwothreefourtwentyfive = 11234.25;
NSNumberFormatter * formatter = [[NSNumberFormatter alloc] init];
[formatter setUsesSignificantDigits:YES];
[formatter setMaximumSignificantDigits:5];
[formatter setMaximumFractionDigits:2];
[formatter setRoundingMode:NSNumberFormatterRoundCeiling];
NSLog(#"%#", [formatter stringFromNumber:[NSNumber numberWithFloat:twofortythreetwentyfive]]);
NSLog(#"%#", [formatter stringFromNumber:[NSNumber numberWithFloat:onetwothreefourtwentyfive]]);
NSLog(#"%#", [formatter stringFromNumber:[NSNumber numberWithFloat:eleventwothreefourtwentyfive]]);
Result:
2012-04-26 16:32:04.481 SignificantDigits[11565:707] 234.25
2012-04-26 16:32:04.482 SignificantDigits[11565:707] 1234.3
2012-04-26 16:32:04.483 SignificantDigits[11565:707] 11235
Code :
#define INTPARTSTR(X) [NSString stringWithFormat:#"%d",(int)X]
#define DECPARTSTR(X) [NSString stringWithFormat:#"%d",(int)(((float)X-(int)X)*100)]
- (NSString*)formatFloat:(float)f
{
NSString* result;
result = [NSString stringWithFormat:#"%.2f",f];
if ([DECPARTSTR(f) isEqualToString:#"0"]) return INTPARTSTR(f);
if ([INTPARTSTR(f) length]==5) return INTPARTSTR(f);
if ([result length]>5)
{
int diff = (int)[result length]-7;
NSString* newResult = #"";
for (int i=0; i<[result length]-diff-1; i++)
newResult = [newResult stringByAppendingFormat:#"%c",[result characterAtIndex:i]];
return newResult;
}
return result;
}
Testing it :
- (void)awakeFromNib
{
NSLog(#"%#",[self formatFloat:234.63]);
NSLog(#"%#",[self formatFloat:1234.65]);
NSLog(#"%#",[self formatFloat:11234.65]);
NSLog(#"%#",[self formatFloat:11234]);
}
Output :
2012-04-26 19:27:24.429 newProj[1798:903] 234.63
2012-04-26 19:27:24.432 newProj[1798:903] 1234.6
2012-04-26 19:27:24.432 newProj[1798:903] 11234
2012-04-26 19:27:24.432 newProj[1798:903] 11234
Here is how I implemented this in my code. I don't know how efficient it is, I hope not bad.
So I create a global NSNumberFormatter
NSNumberFormatter* numFormatter;
and initialize it somewhere:
numFormatter=[[NSNumberFormatter alloc]init];
Then I format number with the following function:
- (NSString*)formatFloat:(Float32)number withOptimalDigits:(UInt8)optimalDigits maxDecimals:(UInt8)maxDecimals
{
NSString* result;
UInt8 intDigits=(int)log10f(number)+1;
NSLog(#"Formatting %.5f with maxDig: %d maxDec: %d intLength: %d",number,optimalDigits,maxDecimals,intDigits);
numFormatter.maximumFractionDigits=maxDecimals;
if(intDigits>=optimalDigitis-maxDecimals) {
numFormatter.usesSignificantDigits=YES;
numFormatter.maximumSignificantDigits=(intDigits>optimalDigits)?intDigits:optimalDigits;
} else {
numFormatter.usesSignificantDigits=NO;
}
result = [numFormatter stringFromNumber:[NSNumber numberWithFloat:number]];
return result;
}
Is this a bug when using maximumFractionDigits and maximumSignificantDigits together on NSNumberForamtter on iOS 8?
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.maximumFractionDigits = 2;
formatter.maximumSignificantDigits = 3;
NSLog(#"%#", [formatter stringFromNumber:#(0.3333)]); // output 0.333 expected 0.33
It works fine if I only use maximumFractionDigits
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.maximumFractionDigits = 2;
NSLog(#"%#", [formatter stringFromNumber:#(0.3333)]); // output expected .33
NSNumberFormatter maximumFractionDigits and maximumSignificantDigits bug
Why does the following code produce "numberFromString = 9.390000000000001" rather than "numberFromString = 9.39"?
NSNumberFormatter *numFormatter = [[NSNumberFormatter alloc] init];
[numFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numFormatter setPositiveFormat:#"$##0.00"];
[numFormatter setNegativeFormat:#"-$##0.00"];
NSNumber *nTCA = [numFormatter numberFromString:#"$9.39"];
NSLog(#"numberFromString = %#", nTCA);
I get the above results on OS X 10.6 and iOS 4.3.3.
What's the best way to correct this error?
Thanks
I suspect you are running into an error as a result of using floating-point precision. The way to fix this is to use NSDecimalNumber instead of NSNumber. There's a great post about this here.
NSDecimalNumber has a + decimalNumberWithString: method. Would that suffice for your purposes?
If I have a number int aNum = 2000000 how do I format this so that I can display it as the NSString 2,000,000?
Use NSNumberFormatter.
Specifically:
NSNumberFormatter *formatter = [NSNumberFormatter new];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle]; // this line is important!
NSString *formatted = [formatter stringFromNumber:[NSNumber numberWithInteger:2000000]];
[formatter release];
By default NSNumberFormatter uses the current locale so the grouping separators are set to their correct values by default. The key thing is to remember to set a number style.
Don't do your own number formatting. You will almost certainly not get all the edge cases right or correctly handle all possible locales. Use the NSNumberFormatter for formatting numeric data to a localized string representation.
You would use the NSNumberFormatter instance method -setGroupingSeparator: to set the grouping separator to #"," (or better yet [[NSLocale currentLocale] objectForKey:NSLocaleGroupingSeparator]; thanks #ntesler) and -setGroupingSize: to put a grouping separator every 3 digits.
There's a static method on NSNumberFormatter that does just what you need:
int aNum = 2000000;
NSString *display = [NSNumberFormatter localizedStringFromNumber:#(aNum)
numberStyle:NSNumberFormatterDecimalStyle];
This way is a little more succinct than creating a new NSNumberFormatter if you don't need to do any additional configuration of the formatter.
Even easier:
NSNumber *someNumber = #(1234567890);
NSString *modelNumberString = [NSString localizedStringWithFormat:#"%#", someNumber];
NSLog(#"Number with commas: %#", modelNumberString);
coworker just taught me this today. #amazing
Think some as i will get this post looking for sample.
So if you are working with number make attention on next params:
setNumberStyle:NSNumberFormatterCurrencyStyle // if you are working with currency
It could be also
setNumberStyle:NSNumberFormatterDecimalStyle
All code is For ARC.
If you are working with Integer and need to get result such as 200,000
int value = 200000;
NSNumberFormatter * formatter = [NSNumberFormatter new];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSString * newString = [formatter stringFromNumber:[NSNumber numberWithInteger:value]];
If you are working with Float and need to get result such as 200,000.00
float value = 200000;
NSNumberFormatter * formatter = [NSNumberFormatter new];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setMaximumFractionDigits:2]; // Set this if you need 2 digits
NSString * newString = [formatter stringFromNumber:[NSNumber numberWithFloat:value]];
EDIT
To have ability to use different digital separators use NSLocale.
Add to code where NSLocale is specified on Locale Identifier:
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"de_DE"]];
or use current local:
[formatter setLocale:[NSLocale currentLocale]];
Swift version
let formatter = NSNumberFormatter()
formatter.numberStyle = .DecimalStyle
formatter.maximumFractionDigits = decimalPlaces
let result = formatter.stringFromNumber(NSNumber(double: 8.0))
By http://ios.eezytutorials.com
An easy solution could be this. My answer is almost same like #Nazir's answer but with a small trick.
double current_balance = 2000000.00;
NSNumberFormatter * formatter = [NSNumberFormatter new];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
//[formatter setNumberStyle:NSNumberFormatterCurrencyStyle]; //if you want for currency with $ sign
[formatter setMinimumFractionDigits:2]; // Set this if you need 2 digits
[formatter setMaximumFractionDigits:2]; // Set this if you need 2 digits
NSString * currency_format = [NSString stringWithFormat:#"%#", [formatter stringFromNumber:[NSNumber numberWithDouble:current_balance]]];
For Swift 4.0
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
let result = formatter.string(from: NSNumber(value: 123456))
For those who need to do it with strings of numbers and not just integers (I.e. Big Numbers) I made the following macro:
#define addCommas(__string) (\
(^NSString *(void){\
NSString *__numberString = __string;\
NSString *__integerPortion = __numberString;\
NSString *__decimalPortion = #"";\
if ([__string containsString:#"."]) {\
__integerPortion = [__numberString componentsSeparatedByString:#"."][0];\
__decimalPortion = st(#".%#", [__numberString componentsSeparatedByString:#"."][1]);\
}\
int __i = (int)__integerPortion.length-3;\
while (__i > 0) {\
__integerPortion = st(#"%#,%#", substringInRange(__integerPortion, 0, __i), substringInRange(__integerPortion, __i, (int)__integerPortion.length));\
__i -= 3;\
}\
__numberString = st(#"%#%#", __integerPortion, __decimalPortion);\
return __numberString;\
})()\
)