Question

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.

Was it helpful?

Solution

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

OTHER TIPS

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);

Simply you can do

$cFormatter->setTextAttribute(NumberFormatter::PAD_BEFORE_PREFIX, '-$')."\n";
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top