9

I'm using the PHP NumberFormatter class to print currency values.

Eg:

  $cFormatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
  $cFormatter->formatCurrency(123, 'USD');
  $cFormatter->formatCurrency(123, 'BRL');
  $cFormatter->formatCurrency(123, 'GBP');

That works fine, and returns "$123.00", "R$123.00", "£123.00" respectively as expected.

But negative numbers are printed "accountancy style", surrounded by brackets, instead of a leading minus "-".

eg:

$cFormatter->formatCurrency(-456, 'USD');

Returns "($456.00)", whereas I want "-$456.00". Surely there's a simple way of doing this?

I can remove the brackets by override the prefix and postfix as follows:

$cFormatter->setTextAttribute(NumberFormatter::NEGATIVE_PREFIX, "-");
$cFormatter->setTextAttribute(NumberFormatter::NEGATIVE_SUFFIX, "");

But then I get no currency symbol eg "-456.00".

Is there some escape code for the currency symbol that I need to use when setting the NEGATIVE_PREFIX attribute?

Edit: I'm happy to set a different locale if that gives me the result I'm looking for.

Edit 2: Looking at the Intl library docs (which is the library used to implement NumberFormatter), the following looked promising:

¤ (\u00A4) : Prefix or suffix : No Currency sign, replaced by currency symbol. If doubled, replaced by international currency symbol. If tripled, replaced by currency plural names, for example, "US dollar" or "US dollars" for America. If present in a pattern, the monetary decimal separator is used instead of the decimal separator.

But this:

$cFormatter->setTextAttribute(NumberFormatter::NEGATIVE_PREFIX, "-¤");

Just prints "-¤123", so no joy.

Edit 3: I think I found the answer, see below.

John Carter
  • 53,924
  • 26
  • 111
  • 144
  • therefromhere: In light of "I'm happy to set a different locale if that gives my the result I'm looking for." Please see my updated answer: use en_AU. – hobodave Jul 21 '09 at 20:22

3 Answers3

17

I've found a slightly less hacky way to bend the en_US locale behaviour to what I'm looking for - the getPattern() / setPattern() functions.

$cFormatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
$sPattern = $cFormatter->getPattern(); // returns "¤#,##0.00;(¤#,##0.00)";

$sMyPattern = "¤#,##0.00;-¤#,##0.00";
$cFormatter->setPattern($sMyPattern);
$cFormatter->formatCurrency(-456, 'USD');  // returns -$456.00
John Carter
  • 53,924
  • 26
  • 111
  • 144
2

By doing so, you are kinda ruining the point of the localization. Since the ¤ represent the dollar sign and your are telling that your pattern always puts the sign in the beginning of the number, which is not the case for every currency. If you want to remove the parenthesis, I would go something more like,

$locale = 'en_US';    
$nf = new \NumberFormatter($locale, \NumberFormatter::CURRENCY); 
$nf->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, $decimals);

$pattern = str_replace(array('(',')'),'',$nf->getPattern());
$nf->setPattern($pattern);

echo $nf->format($number);
Johnny Dew
  • 971
  • 2
  • 13
  • 29
-1

Simply you can do

$cFormatter->setTextAttribute(NumberFormatter::PAD_BEFORE_PREFIX, '-$')."\n";
vikram eklare
  • 800
  • 7
  • 25
  • 1
    Why should the OP "try this"? A **good answer** will always have an explanation of what was done and why it was done that way, not only for the OP but for future visitors to SO that may find this question and be reading your answer. – Maximilian Ast Jul 29 '16 at 12:20