Tell me more ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

goal:
write the most concise function that formats a (String) decimal into a currency format in Apex. Feel free to trainwreck the code for points, I've kept mine exploded for readability purposes.

share|improve this question
Is this an actual problem you are facing or just a way to entertain the troops? Typically we don't allow "getting to know you" -type questions posted strictly for social and entertainment value. Perhaps your question is better suited to codegolf.stackexchange.com? – Robert Cartaino Aug 16 '12 at 17:55
1  
it was a problem I was facing, and I solved it with the code I supplied. I had a hunch I was recreating the wheel so I used the code golf format to elicit responses. I have seen other examples of code golf in the past on SE. Of course a new exchange would be created for that purpose, cant seem to keep up with you guys ;) – ebt Aug 16 '12 at 17:59
I didn't have a problem with this question specifically, as long as the context and motivation was sound. Enjoy. – Robert Cartaino Aug 16 '12 at 18:05

6 Answers

up vote 4 down vote accepted

Here's one that's shorter AND is locale safe:

public static String currency(String i) {
    String s = ( Decimal.valueOf(i==null||i.trim()==''?'0':i).setScale(2) + 0.001 ).format();
    return s.substring(0,s.length()-1);
}

Check out Number Format in the list of supported locales. There's "1.000,00" and "1 000.00" amongst others. Not everyone uses "1,000.00" so we shouldn't assume that in a formatter. Decimal's format() method is locale aware.

share|improve this answer
I could do it all in one line if Apex's substring() acccepted negatives in the second argument for chopping off the right. You'd have blah.format().substring(0,-1) – RickMeasham Aug 12 '12 at 9:01
1  
Your method doesn't handle empty strings, I made a slight edit to fix that. Basically changing your (i==null?'0':i) to (i==null||i.trim()==''?'0':i) – E.J. Wilburn Aug 12 '12 at 14:28
Out of interest, why is 0.001 added after the rounding and before the call to format? – Daniel Ballinger Aug 29 '12 at 0:45
Adding 0.001 means we have two zeroes after the decimal place without altering those two decimal places. The format then strips off the 1 – RickMeasham Sep 12 '12 at 10:29

Ok - first, I'm not actually recommending the following approach. It's more of an intellectual exercise - an exploration of a different path to a solution.

First, create the following Apex page:

< apex:page Controller="currencyfuncontroller" showHeader="false" sidebar="false" >
    < apex:outputField id="formattedamount" value="{!DummyOpportunity.Amount}" />
< /apex:page>

The controller is as follows:

public class currencyfuncontroller
{
   public Opportunity getDummyOpportunity()
   {
       String currencystring = 
         Apexpages.currentPage().getParameters().get('currencystring');
       Decimal currencyvalue = 0;
       try
       {
           currencyvalue = Decimal.ValueOf(currencystring);
       } catch(Exception ex) {}
       Opportunity op = new Opportunity(amount = currencyvalue);
       return op;
   }
}

Here's some simple code to use it:

ApexPages.PageReference pr = Page.currencyfun;
pr.getParameters().put('currencystring','1.56');
String contents = pr.GetContent().toString();
system.debug(contents);

You still need to parse out the actually currency value - but that's easy enough to do use a regular expression or some substring work, so I left it out here. I also cheated by using an exception handler instead of the (better) validation shown in other answers - just to keep things simple.

What does this approach accomplish?

  • The formatting now includes the correct currency symbol for the user's locale (and currency formatting should it differ from standard decimal formatting).
  • You could extend this to include a parameter for the currency to use and use that info to set the currency type for the opportunity. On multi-currency organizations this should provide automatic currency conversion to the current locale with the formatting (standard SFDC formatting on multi-currency organizations).

Again - If I really needed this I'd probably actually write the code to lookup currency symbols, examine the current and corporate currency, and do the necessary conversions and formatting directly. But that's quite a bit of code (especially on orgs using advanced currency management).

Ultimately my point is - the original question was asking for formatting a decimal string into currency format, and the job isn't really done until you have the correct currency symbol and multi-currency handling in place :-)

share|improve this answer

Of course, it all depends on your use case. Most of the time, you don't need to do this in Apex since the value is destined either for display on a VisualForce page or storage via a Currency field. That said, you'd be able to do this in pure Apex if it weren't for the type restriction on the String.format(...) method. Requiring a List<String> for the arguments prevents you from doing it in pure Apex, at least easily.

If the point of the Apex code is to provide a value for display in a VisualForce page, then Apex really need not do anything but provide the raw decimal value:

<apex:outputText value="Total: {0, number, currency}">
  <apex:param value="{!aDecimalValue}"/>
</apex:outputText>

No need for a dummy SObject with a currency field, although that certainly works.

share|improve this answer
my particular requirement needed dynamic json, using hardcorded vf tags mixed with json wasnt a direction I wanted to take. – ebt Aug 17 '12 at 20:05

670 characters

public static String currency(String input){
    if(input == null){return '0.00';}
    if(input.indexOf('.') == -1){input = input+'.00';}
    if(input.length() == 5){return input+'0';}
    String newValue = input.substring(input.indexOf('.'));
    newValue = String.valueOf(Decimal.valueOf(newValue).setScale(2));
    newValue = newValue.substring(newValue.indexOf('.'));
    input = input.substring(0,input.indexOf('.'));
    Integer sz = input.length();
    Integer n=0;
    for(Integer i = sz - 1;i > -1;i--){
        if(n!= 0 && math.mod(n,3) == 0)
            newValue = input.substring(i,i+1)+','+newValue;
        else
            newValue = input.substring(i,i+1)+newValue;
        n++; 
    }
    return newValue;
}
//unit test, doesnt count
static testmethod void test_currency(){
    system.assertEquals('2,105.00',currency('2105.0'));
    system.assertEquals('320.00',currency('320.0'));
    system.assertEquals('1,500.26',currency('1500.256'));
    system.assertEquals('0.00',currency('0.0'));
    system.assertEquals('0.00',currency(null));
    system.assertEquals('10,000,123.56',currency('10000123.558'));
} 
share|improve this answer
Should the last assert read system.assertEquals('1,500.26',currency('1500.26')); – David Gillen Aug 10 '12 at 22:31
the value being passed in should be .256, its testing the decimal rounding part of the method. – ebt Aug 10 '12 at 22:33

The following should do the trick, with the assumption that your locale for currency formatting is correct. Edited to handle null being passed, and zero values after the decimal.

public static String currency(String input) {
    if ( input == null ) {
        return '0.00';
    }

    Decimal d1 = Decimal.valueOf(input).setScale(2);
    String str = d1.format();
    if( !str.contains('.' ) ) {
        str = str + '.00';
    }

    return str;
}
share|improve this answer
failed the first test: 15:44:29.595 (595496000)|FATAL_ERROR|System.AssertException: Assertion Failed: Expected: 2,105.00, Actual: 2,105 – ebt Aug 10 '12 at 22:46
Believe that edit should do it. – David Gillen Aug 10 '12 at 23:10
Not for 0.1. It returns 0.1 rather than 0.10 – RickMeasham Aug 12 '12 at 8:44

Rarely should you ever need to format variables like that in Apex. Since that's typically a view issue, I tend to rely on apex:outputField for that scenario in Visualforce. Kibitzer has the right idea.

share|improve this answer
Depends on your definition of rare: this post wouldn't exist and neither would ideas like this sites.secure.force.com/success/ideaView?id=08730000000KlHoAAK if there wasn't a need sometimes for this functionality e.g. building message strings in Apex code. I suggest that salesforce's product managers don't spend enough time using their product to understand how many gaps there are in what they provide. And they do a great job of ignoring the ideas forum they created. – Keith C Feb 12 at 16:02

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.