function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
TLFTLF 

Currency formatting... again

Ok, I know there are a lot of posts on this topic, and I am familiar with the two Visualforce techniques for doing this (using an outputField bound to an SObject currency field, and using the outputText value="{0,number,###,##0.00}" ). However, in my use case, I'm trying to display a currency value in the title of a pageBlock:

 

 

<apex:pageBlock title="Refund Amount: {!refundAmount}" >

 

I can't really use the outputText or outputField options here, so I think I need to do the formatting in my controller. The Apex documentation states that String.format(String, List<String>) works "in the same manner as apex:outputText." Has anyone actually used this method to format a Decimal value into a properly formatted currency String in Apex code?

Best Answer chosen by Admin (Salesforce Developers) 
ssikorassikora

It does work. Execute this in the ExecuteAnonymous:

 

 

Decimal rA = 1298763.86;
List<String> args = new String[]{'0','number','###,###,##0.00'};
String s = String.format(rA.format(), args);
System.debug(s);

 

 

All Answers

TLFTLF

I tried executing the following Apex code:

 

 

Decimal refundAmount = 129;
refundAmount.setScale(2);
List<String> args = new List<String>();
args.add(refundAmount.format());
String s = String.format('{0,number,currency}', args);

 

It throws the following exception: System.StringException: Cannot format given Object as a Number. Any ideas?

 

John De SantiagoJohn De Santiago

You should be able to use a face tag to accomplish this.

 

Try this:

 

<apex:pageBlock>
 <apex:facet name="header">
    <apex:outputText value="your title text here"/>
 </apex:facet>
</apex:pageBlock>

 

 

TLFTLF

I thought of this approach too. That gets the title formatted properly, but you now lose all other styling of the title bar. I can probably brute force it by putting the same html elements and CSS classes that normally appear in the title bar, into my header facet.

 

I'd really like to know if anybody has ever gotten the Apex String.format(String, List<String>) method to work properly. It seems it simply does not work. If you can format it with Visualforce, why can't the same formatting be applied server-side, using Apex?

ssikorassikora

It does work. Execute this in the ExecuteAnonymous:

 

 

Decimal rA = 1298763.86;
List<String> args = new String[]{'0','number','###,###,##0.00'};
String s = String.format(rA.format(), args);
System.debug(s);

 

 

This was selected as the best answer
TLFTLF

Thanks ssikora! Obviously I had the String.format call syntax wrong.

TechOwlTechOwl

This approach does not actually work when there is only ONE digit after the decimal place.

 

For example,this code below generates $1,298,763.5 and NOT $1,298,763.50 which is the desired result - any ideas?

 

Double pDouble = 1298763.5;
Decimal rA = Decimal.valueOf(pDouble);
list<String> args = new String[]{'0','number','###,###,##0.00'};
String s = String.format(rA.format(), args);
system.Debug('\n\n$'+s+'\n\n');

JFraileJFraile

Hi.

 

I've run into the same problem. if the number has no decimals, then no zeros are added in the decimal places. What I do is add the zeros myself with some code like

public string point = '.' ;

if (!ptemp.PrecioUnitariofusion__c.contains(point))
{ptemp.PrecioUnitariofusion__c = ptemp.PrecioUnitariofusion__c + ',00 €' ;}

 

If you use the format in a VF, it works fine, zeros are added in decimal places.

<apex:outputText value="{0,number,###,###,##0.00}"><apex:param value="{!ptemp.PrecioUnitariofusion__c}"/></apex:outputText>

 

The problem when using the outputText formatting is that numbers won't change from xxx,xxx,xxx.00 to xxx.xxx.xxx,00, I mean change point decimal separation to comma decimal separation, wich is done using the apex string format....

RalphCallawayRalphCallaway
String.format doesn't work for anything except basic stirng substitution, contrary to the docs.  If you try and do anything else you just get a string exception, cannot format blah, blah blah.

@TechOwl, the reason that approach doesn't work is the args aren't the formatting instructions, they're what's merged in, since ra.format() doesn't have any merge elements it just gets spit right back out as it came in.

list<String> args = new String[]{'0','number','###,###,##0.00'};
String s = String.format('0:{0} 1:{1} 2:{2}', args);
// => "0:0 1:number 2:###,###,##0.00"

In theory this would work, but it just blows up with "System.StringException: Cannot format given Object as a Number", epic fail

String format = 'Currency: {0, number, currency}';
Decimal val = 1000;
String[] input = new String[] { val.format(), val.format() };
String output = String.format(format, input);
system.debug('output: ' + output);


Vlad DarevskiyVlad Darevskiy
Or you can go : 

Decimal value = 12.1234567;
value = value.setScale(2);  
System.assert( 12.12 == value );  
Mitesh SuraMitesh Sura
I am sorry but the Best Answer chosen by admin does not work. It does not respect the format in the args but always defaults to user locale.
Decimal rA = 1298763.86;
List<String> args = new String[]{'0','number','###.###.##0,00'};
String s = String.format(rA.format(), args);
System.debug(s);
One would expect the output to be 1.298.763,86 but as my locale is US, it spits out 1,298,763.86 I am not sure why this was marked as answer??
While we are at the topic, what is best way to format decimal numbers as per the argument provided?


 
Admin ZSPulse08Admin ZSPulse08
The accepted answer is somewhat misleading - it isn't using the specified formatting string at all. You get the exact same result if you do:
Decimal rA = 1298763.86;
System.debug(rA.format());
The call to `String.format` is basically a no-op, the decimal is being formatted per the user's locale using `Decimal.format`
docbilldocbill
It is really sad the format method does not work properly in apex.  You can pass in a list of objects such as decimals to format, but the are converted to strings with toString() instead of using the formatting specified.   The following is a method I used in a utility class to handle displaying the correct number of decimal places:

    /**
     * Useful to utility to format a decimal with specified number of decimal digits.
     * @param value to format as a string
     * @param scale number of decimal digits
     * @return the formatted string or nill if value was null
     */
    public static String formatDecimal(Decimal value, Integer scale) {
        String retval = '';
        if(value != null) {
            if(scale == null) {
                scale = value.scale();
            }
            retval = value.format();
            if(scale <= 0) {
                retval = Decimal.valueOf(value.round()).format();
            }
            else if(scale > 0 && scale <= 18) {
                Long modulus = Long.valueOf('1000000000000000000'.left(scale+1));
                Long msd = (Math.abs(value)*modulus).round();
                Long lsd = Math.mod(msd,modulus);
                msd = ((value > 0)?(msd - lsd):(lsd - msd))/modulus;
                retval = Decimal.valueOf(msd).format()+'.'+(String.valueOf(modulus+lsd).substring(1));
            }
        }
        return retval;
    }
 
J BengelJ Bengel
Feel free to try other use cases, but for currency, this should do the trick.
List<Decimal> amts = new List<Decimal>{15.00,15,15.1,15.10,15.25,15.01};
for(Decimal amt: amts){
    System.debug('input amount: ' +amt);
    System.debug('chaining setScale to .toPlainString: '+amt.setScale(2).toPlainString());
}

16:21:29:003 USER_DEBUG [3]|DEBUG|input amount: 15.00
16:21:29:003 USER_DEBUG [4]|DEBUG|chaining setScale to .toPlainString: 15.00
16:21:29:003 USER_DEBUG [3]|DEBUG|input amount: 15
16:21:29:003 USER_DEBUG [4]|DEBUG|chaining setScale to .toPlainString: 15.00
16:21:29:003 USER_DEBUG [3]|DEBUG|input amount: 15.1
16:21:29:003 USER_DEBUG [4]|DEBUG|chaining setScale to .toPlainString: 15.10
16:21:29:003 USER_DEBUG [3]|DEBUG|input amount: 15.10
16:21:29:003 USER_DEBUG [4]|DEBUG|chaining setScale to .toPlainString: 15.10
16:21:29:003 USER_DEBUG [3]|DEBUG|input amount: 15.25
16:21:29:004 USER_DEBUG [4]|DEBUG|chaining setScale to .toPlainString: 15.25
16:21:29:004 USER_DEBUG [3]|DEBUG|input amount: 15.01
16:21:29:004 USER_DEBUG [4]|DEBUG|chaining setScale to .toPlainString: 15.01