ios numberformatter currency remove trailing decimals if 0 - ios

I want to format my number into a currency string. These are the following cases
25.00 => $25
25.43 => $25.43
25.4 => $25.40
0.00 -> $0
Is there a way to do this in NSNumberFormatter?
This is my code right now:
NSNumberFormatter *fmt = [[NSNumberFormatter alloc] init];
[fmt setNumberStyle:NSNumberFormatterCurrencyStyle];
[fmt setCurrencyCode:#"USD"];
However that fails for my first and last examples.
I also tried:
NSNumberFormatter *fmt = [[NSNumberFormatter alloc] init];
[fmt setPositiveFormat:#"$0.##"];
However that fails for my third case. Any suggestions?

Change the number of fraction digits based upon whether or not the number is whole.
- (NSString *)stringFromNumber:(NSNumber *)number
{
BOOL isWholeNumber = (roundf(number.doubleValue) == number.doubleValue);
self.currencyNumberFormatter.maximumFractionDigits = self.currencyNumberFormatter.minimumFractionDigits = isWholeNumber ? 0 : 2;
NSString *str = [self.currencyNumberFormatter stringFromNumber:number];
return str;
}

I don't think there's a way to do this using a plain NSNumberFormatter. You could set the minimum and maximum fraction digits to 0 just for formatting integers in a subclass of NSNumberFormatter:
#interface MyCurrencyFormatter : NSNumberFormatter
#end
#implementation MyCurrencyFormatter
- (id)init {
if ((self = [super init])) {
[self setNumberStyle:NSNumberFormatterCurrencyStyle]];
[self setCurrencyCode:#"USD"];
}
return self;
}
- (NSString *)stringFromNumber:(NSNumber *)aNumber {
NSInteger minimumFractionDigits = [self minimumFractionDigits];
NSInteger maximumFractionDigits = [self maximumFractionDigits];
if ([self isInteger:aNumber]) {
[self setMinimumFractionDigits:0];
[self setMaximumFractionDigits:0];
}
NSString *formattedNumber = [super stringFromNumber:aNumber];
[self setMinimumFractionDigits:minimumFractionDigits];
[self setMaximumFractionDigits:maximumFractionDigits];
return formattedNumber;
}
- (BOOL)isInteger:(NSNumber *)aNumber {
NSDecimal decimalValue = aNumber.decimalValue;
NSDecimalRound(&decimalValue, &decimalValue, 0, NSRoundDown);
NSDecimalNumber *roundedValue = [[NSDecimalNumber alloc] initWithDecimal:decimalValue]
return [aNumber isEqualToNumber:roundedValue];
}
#end
This should handle international number formats as well.
Credit to this post for determining if a number is an integer.

I am using the following solution in Swift. It is based on jowie's answer except I do not want to change maximumFractionDigits if my number is not whole. In some countries more than 2 digits are used for prices.
if(price==price.decimalNumberByRoundingAccordingToBehavior(nil))
{
numberFormatter.maximumFractionDigits=0
numberFormatter.minimumFractionDigits=0
}
let priceStr = numberFormatter.stringFromNumber(price)!

A "swifty" way to achieve the desired result, but remain flexible is to set a range by setting the minimum and maximum fraction digits to show:
let price: NSDecimalNumber // 299.0
let priceLocale: Locale // .current
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = priceLocale
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 0
let result = formatter.string(from: price) ?? "" // 299 $

Related

How to format a float value in Objective-C

- (NSString *)_stringToFloat:(NSNumber *)number {
if (number && number > 0) {
return [NSString stringWithFormat:#"%.2f",[number floatValue]];
}
return #"0.0";
}
Using:
_lblAppointmentFee.text = [[NSString alloc]initWithFormat:#"%#",[self_stringToFloat:[_dicObject objectForKeyNotNull:#"rate"]]];
How can I can return "5.21" for a value of 5.21 and return "5" for a value of 5.00?
Use an NSNumberFormatter. Set the desired fraction digits.
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
nf.numberStyle = NSNumberFormatterDecimalStyle;
nf.minimumFractionDigits = 0;
nf.maximumFractionDigits = 2;
NSString *result = [nf stringFromNumber:#(5.12)];
This gives a result of "5.12" while:
result = [nf stringFromNumber:#(5.00)];
gives a result of "5".
This also has the added bonus of properly formatting the result based on the user's locale.

Time Format so there's only 4 digits with a ":" in the middle

I want the concatenated NSString I have to be output in the format "00:00", the 0s being the digits in the concatenated string. And if there are not enough characters in the NSString, the other digits are made to be 0.
And if there are more than 4 digits than I want to only have the furthest right digits.
I have done this in Java before, I am assuming it's possible in Objective-C as well.
UIButton *button = sender;
NSString *concatenated = [self.input stringByAppendingString: button.titleLabel.text];
self.input = concatenated;
self.userOutput.text = self.input;
For example, I might get "89" as my concatenated string. I then want, self.input = 00:89.
OR
if I get 89374374 from my concatenated string, I then want self.input = 43:74.
I hope I am being clear
The following method should give the desired output:
- (NSString *)getFormattedTimeStringFromString:(NSString *)string
{
int input = [string intValue];
int mins = input % 100;
input /= 100;
int hours = input % 100;
return [NSString stringWithFormat:#"%02d:%02d", hours, mins];
}
You can use this by calling
self.input = [self getFormattedTimeStringFromString:concatenated];
Like this:
NSDateFormatter * df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"HH:mm"];
NSString *dateTimeStr = [df stringFromDate:[NSDate date]];
if ([concatenated length] == 2) {
self.input = [NSString stringWithFormat:#"00:%#",concatenated];
}
else
{
NSString *test = [concatenated substringFromIndex:[concatenated length] -4];
self.input = [NSString stringWithFormat:#"%#:%#",[test substringToIndex:2],[test substringFromIndex:[test length]-2]];
}
Please try above code it will fail if [concatenated length] is 3 or 1 , modify it accordingly

How would I get a list of world currencies and their corresponding symbols (i.e. $, £, ¥, €, etc.) in iOS? [duplicate]

I have get currency code (Eg: USD, EUR, INR) from webservice response. I need to show the currency symbols for the corresponding currency code. If the currency code is USD, i need to show $, if the currency code is EUR i need to show €. How can i do this? Please suggest any idea or sample code to do this. Please help me. Thanks in advance.
This code works charm in my project. I will share this to you all.
NSString *currencyCode = #"EUR";
NSLocale *locale = [[[NSLocale alloc] initWithLocaleIdentifier:currencyCode] autorelease];
NSString *currencySymbol = [NSString stringWithFormat:#"%#",[locale displayNameForKey:NSLocaleCurrencySymbol value:currencyCode]];
NSLog(#"Currency Symbol : %#", currencySymbol);
Thanks.
Swift 4 version
Finding locale by currency code:
let localeGBP = Locale
.availableIdentifiers
.lazy
.map { Locale(identifier: $0) }
.first { $0.currencyCode == "GBP" }
print(localeGBP?.currencySymbol) // £
Formatting currency
if let locale = localeGBP {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = locale
let result = formatter.string(from: 100000) // £100,000.00
}
Edit:
Why .lazy? Without it the loop would run over all the locale identifiers and return the first one which matches. That's about 700ish identifiers, and if the first one is the one you want then you have wasted creating 699 Locales :) With .lazy in there it automatically stops at the first matching one. In my case it reduces the number of times through the loop from 710 down to 22 when converting "GBP". This isn't important if you are only doing this once, but if you're doing this a number of times (i.e. over an array of symbols) then it's an easy way to get a bit more efficiency.
This code is what you are looking for though not very efficient because of loop for locales. Still it works correctly for all currency codes, not just for eur or usd. Hope this will help you.
- (NSLocale *) findLocaleByCurrencyCode:(NSString *)_currencyCode
{
NSArray *locales = [NSLocale availableLocaleIdentifiers];
NSLocale *locale = nil;
for (NSString *localeId in locales) {
locale = [[[NSLocale alloc] initWithLocaleIdentifier:localeId] autorelease];
NSString *code = [locale objectForKey:NSLocaleCurrencyCode];
if ([code isEqualToString:_currencyCode])
break;
else
locale = nil;
}
return locale;
}
- (NSString *)findCurrencySymbolByCode:(NSString *)_currencyCode
{
NSNumberFormatter *fmtr = [[NSNumberFormatter alloc] init];
NSLocale *locale = [self findLocaleByCurrencyCode:_currencyCode];
NSString *currencySymbol;
if (locale)
[fmtr setLocale:locale];
[fmtr setNumberStyle:NSNumberFormatterCurrencyStyle];
currencySymbol = [fmtr currencySymbol];
[fmtr release];
if (currencySymbol.length > 1)
currencySymbol = [currencySymbol substringToIndex:1];
return currencySymbol;
}
Use it this way:
NSString *currencySymbol = [self findCurrencySymbolByCode:currencyCode];
NSLocale will happily tell you the currency symbol used by a particular locale:
[locale objectForKey:NSLocaleCurrencySymbol];
It'll also tell you the currency code:
[locale objectForKey:NSLocaleCurrencyCode];
So all you have to do now is look up the locale that corresponds to a given code. There's no built-in method (that I'm aware of) to do this directly, so loop through all the known locales and pick the one that matches. #Umka's answer has a good example of this in the -findLocaleByCurrencyCode: method.
You could optimise the process by building your own lookup table, rather than iterating through all locales each time. You may need to handle the possibility of duplicate currency codes too, which would require some heuristic for deciding which is the most likely locale.
Building on code from #Mike Abdullah and #Umka, here are some functions in Swift.
func findCodeAndSymbolForAllLocales() {
let locales = NSLocale.availableLocaleIdentifiers()
for localeId in locales {
let locale = NSLocale(localeIdentifier: localeId)
if let code = locale.objectForKey(NSLocaleCurrencyCode) as? String,
let symbol = locale.objectForKey(NSLocaleCurrencySymbol) {
print("\(code) \(symbol)")
}
}
}
func findCurrencySymbolByCode(currencyCode:String) -> String? {
guard let locale = findLocaleByCurrencyCode(currencyCode) else {
print("locale for \(currencyCode) is nil")
return nil
}
return locale.objectForKey(NSLocaleCurrencySymbol) as? String
}
func findLocaleByCurrencyCode(currencyCode:String) -> NSLocale? {
let locales = NSLocale.availableLocaleIdentifiers()
var locale:NSLocale?
for localeId in locales {
locale = NSLocale(localeIdentifier: localeId)
if let code = locale!.objectForKey(NSLocaleCurrencyCode) as? String {
if code == currencyCode {
return locale
}
}
}
return locale
}
NSNumberFormatter * formatter = [NSNumberFormatter new];
formatter.numberStyle = NSNumberFormatterCurrencyStyle;
NSString * localeIde = [NSLocale localeIdentifierFromComponents:#{NSLocaleCurrencyCode: currencyCode}];
formatter.locale = [NSLocale localeWithLocaleIdentifier:localeIde];
NSString * symbol = formatter.currencySymbol;
One way is to start with a valid locale (e.g. the user current locale) and then override the currency code. Simple and efficient and allows you to use the newly constructed locale to configure a currency formatter in order to display a string according to the user's locale preferences:
NSLocale* locale = [NSLocale currentLocale];
if (_currencyCode) {
NSMutableDictionary* components = [[NSLocale componentsFromLocaleIdentifier:locale.localeIdentifier] mutableCopy];
components[NSLocaleCurrencyCode] = _currencyCode;
locale = [[NSLocale alloc] initWithLocaleIdentifier:[NSLocale localeIdentifierFromComponents:components]];
}
return locale.currencySymbol;
NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
this is for US currency style
NSNumberFormatter *numberFormatter = [[[NSNumberFormatter alloc] init] autorelease];
//[numberFormatter setCurrencySymbol:#"Rs"];
[numberFormatter setNumberStyle:#"en_IN"];
This is for indian
Swift
let locale = NSLocale(localeIdentifier: currencyCode)
let currencySymbol = locale.displayName(forKey: .currencySymbol, value: currencyCode) ?? currencyCode
print("Currency symbol: \(currencySymbol)")

Having trouble using NSNumberFormatter for currency conversion in iOS

I have a UITextField that receives numeric input from the user in my application. The values from this textfield then get converted into currency format using NSNumberFormatter within my shouldChangeCharactersInRange delegate method. When I enter the number "12345678", the number gets correctly converted to $123456.78 (the numbers are entered one digit at a time, and up to this point, everything works smoothly). However, when I enter another digit after this (e.g. 9), rather than displaying "1234567.89", the number "1234567.88" is displayed. If I enter another number after that, a totally different numbers after this (I'm using the number key pad in the application to enter the numbers. Here is the code that I have:
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
modifiedValue = [formatter stringFromNumber:[NSNumber numberWithFloat:[modifiedValue floatValue]]];
textField.text = modifiedValue;
The line that causes this unusual conversion is this one:
modifiedValue = [formatter stringFromNumber:[NSNumber numberWithFloat:[modifiedValue floatValue]]];
Can anyone see why this is?
It's likely to be a rounding error when doing the string->float conversion. You shouldn't use floats when dealing with currency. You could use a NSDecimalNumber instead.
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
// Below 2 lines if converting from a "currency" string
NSNumber *modifiedNumber = [formatter numberFromString:modifiedValue]; // To convert from the currency string to a number object
NSDecimalNumber *decimal = [NSDecimalNumber decimalNumberWithDecimal:[modifiedNumber decimalValue]];
// OR the below line if converting from a non-currency string
NSDecimalNumber *decimal = [NSDecimalNumber decimalNumberWithString:modifiedValue];
modifiedValue = [formatter stringFromNumber:decimal]; // Convert the new decimal back to a currency string
You may also consider making the number formatter lenient - often helps with user entered data.
[formatter setLenient:YES];
When I'm running number conversions to currency, I usually run this code:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *text = _textField.text;
NSString *decimalSeperator = #".";
NSCharacterSet *charSet = nil;
NSString *numberChars = #"0123456789";
// the number formatter will only be instantiated once ...
static NSNumberFormatter *numberFormatter;
if (!numberFormatter)
{
[numberFormatter setLocale:[NSLocale currentLocale]];
numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
numberFormatter.maximumFractionDigits = 10;
numberFormatter.minimumFractionDigits = 0;
numberFormatter.decimalSeparator = decimalSeperator;
numberFormatter.usesGroupingSeparator = NO;
}
// create a character set of valid chars (numbers and optionally a decimal sign) ...
NSRange decimalRange = [text rangeOfString:decimalSeperator];
BOOL isDecimalNumber = (decimalRange.location != NSNotFound);
if (isDecimalNumber)
{
charSet = [NSCharacterSet characterSetWithCharactersInString:numberChars];
}
else
{
numberChars = [numberChars stringByAppendingString:decimalSeperator];
charSet = [NSCharacterSet characterSetWithCharactersInString:numberChars];
}
// remove amy characters from the string that are not a number or decimal sign ...
NSCharacterSet *invertedCharSet = [charSet invertedSet];
NSString *trimmedString = [string stringByTrimmingCharactersInSet:invertedCharSet];
text = [text stringByReplacingCharactersInRange:range withString:trimmedString];
// whenever a decimalSeperator is entered, we'll just update the textField.
// whenever other chars are entered, we'll calculate the new number and update the textField accordingly.
if ([string isEqualToString:decimalSeperator] == YES)
{
textField.text = text;
}
else
{
NSNumber *number = [numberFormatter numberFromString:text];
if (number == nil)
{
number = [NSNumber numberWithInt:0];
}
textField.text = isDecimalNumber ? text : [numberFormatter stringFromNumber:number];
}
return NO; // we return NO because we have manually edited the textField contents.
}
The link explaining this is Re-Apply currency formatting to a UITextField on a change event
Hope this works!

Convert String to Double with Currency

NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle: NSNumberFormatterCurrencyStyle];
double value = [[numberFormatter numberFromString: ProviderTripRate.text] doubleValue];
[User setDouble:value forKey:#"Trip_Rate"];
NSLog(#" %# %f " , ProviderTripRate.text , value );
If the data inside ProviderTripRate.text is 2.75 then value is 0 wrong
If the data inside ProviderTripRate.text is $2.75 then value is 2.75 correct
How do you reliably convert from the string to a double value
NOTE that the text string may or may NOT have the local currency symbol ($ as shown above)
but it should always convert
Thanks in advance
Try this:
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle: NSNumberFormatterCurrencyStyle];
NSNumber* number = [numberFormatter numberFromString:ProviderTripRate.text]
if (!number) {
[numberFormatter setNumberStyle: NSNumberFormatterDecimalStyle];
number = [numberFormatter numberFromString:ProviderTripRate.text];
}
double value = [number doubleValue];
Try this:
if ([providerTripRate.text hasPrefix:#"$"]) {
// use NSNumberFormatter to obtain the value
} else {
float theValue = [providerTripRate.text doubleValue];
}
etc.
extension String {
/// Creates a Double from the string
///
/// Tries various ways of extracting a number, currently handling the following formats
/// - 1000
/// - 1000.00
/// - 1,000.00
/// - $1,000.00
///
/// - Returns: Double value, or 0.0 if a non numerical String is passed
func asDouble() -> Double {
if let double = Double(self) {
return double
}
let formatter = NumberFormatter()
if let number = formatter.number(from: self) {
return number.doubleValue
}
formatter.numberStyle = .currency
if let number = formatter.number(from: self) {
return number.doubleValue
}
formatter.currencySymbol = ""
formatter.internationalCurrencySymbol = ""
if let number = formatter.number(from: self) {
return number.doubleValue
}
return 0
}
}

Resources