Soonts
Soonts

Reputation: 21936

iOS: formatting decimal numbers

I have an NSDecimalNumber representing a money amount. I want to print it as "999 999 999 999 999 999,00", regardless on the locale. How do I do that?

NSNumberFormatter prints me 1 000 000 000 000 000 000,00 instead (it seems Apple engineers never designed the iPhone to be a platform for financial software).

[NSDecimalNumber description] and [NSDecimalNumber descriptionWithLocale] both print correct value. How can I format the result, with grouping separator set to @"\u2006", decimal separator to @"**,**", and exactly 2 decimal digits after the decimal seperator?

Thanks in advance!

Update: Here's my solution, 10x to Sulthan:

@implementation NSDecimalNumber(MiscUtils)

-(NSString*)moneyToString
{
    static NSDecimalNumberHandler* s_handler = nil;
    if( !s_handler )
        s_handler = [ [ NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:2 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO ] retain ];

    NSDecimalNumber *dec = [ self decimalNumberByRoundingAccordingToBehavior:s_handler ];
    NSString* str = [ dec description ];
    NSRange rDot = [ str rangeOfString:@"." ];
    int nIntDigits = str.length;
    int nFracDigits = 0;
    if( rDot.length > 0 )
    {
        nIntDigits = rDot.location;
        nFracDigits = str.length - ( rDot.location + 1 );
    }
    int nGroupSeparators = ( nIntDigits - 1 ) / 3;

    NSMutableString* res = [ NSMutableString stringWithCapacity:nIntDigits + nGroupSeparators + 3 ];
    NSString *groupingSeparator = @"\u2006";

    int nFirstGroup = ( nIntDigits % 3 );
    int nextInd = 0;
    if( nFirstGroup )
    {
        [ res appendString:[ str substringToIndex:nFirstGroup ] ];
        nextInd = nFirstGroup;
    }

    while( nextInd < nIntDigits )
    {
        if( res.length > 0 )
            [ res appendString:groupingSeparator ];
        [ res appendString:[ str substringWithRange:NSMakeRange( nextInd, 3 ) ] ];
        nextInd += 3;
    }

    if( nFracDigits > 0 )
    {
        if( nFracDigits > 2 )
            nFracDigits = 2;
        [ res appendString:@"," ];
        [ res appendString:[ str substringWithRange:NSMakeRange( rDot.location + 1, nFracDigits ) ] ];
        while( nFracDigits < 2 )
        {
            [ res appendString:@"0" ];
            nFracDigits++;
        }
    }
    else
        [ res appendString:@",00" ];
//  DLog( "formatDecimal: %@ -> %@", dec, res );
    return res;
}
@end 

Upvotes: 3

Views: 6329

Answers (2)

Son Nguyen
Son Nguyen

Reputation: 3491

Try this:

    NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"US"];

    NSNumberFormatter *frm = [[NSNumberFormatter alloc] init];
    [frm setNumberStyle:NSNumberFormatterDecimalStyle];
    [frm setMaximumFractionDigits:2];
    [frm setMinimumFractionDigits:2];
    [frm setLocale:usLocale];
    NSString *formattedNumberStr = [frm stringFromNumber:[NSNumber numberWithFloat:floatToRound]];

    [frm release];
[usLocale release];

    return formattedNumberStr;

Upvotes: 6

Sulthan
Sulthan

Reputation: 130102

I had the same problem. I was told that NSNumberFormatter converts everything to a double first. How did I solve it? It's easy, just write your own formatter.

  1. First round the decimal to 2 decimal digits.
  2. Get its description as a string.
  3. Find decimal point (.) in the string and replace it with the one you want.
  4. After every three digits from the decimal point to the left, insert a grouping separator.

Upvotes: 3

Related Questions