Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get NumberFormatter to print negative currency values with a minus sign?

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.

like image 582
John Carter Avatar asked Jul 21 '09 18:07

John Carter


People also ask

How do you display negative currency?

The negative sign before the number but behind the currency symbol. The negative sign after the number. Enclosed in parentheses. Most currencies use the same decimal and thousands separator that other numbers in the locale use, but this is not always true.

How do you make a negative dollar sign?

The minus sign is always the leftmost: -(rest of the symbols). The currency symbol is always adjacent to the figure: €(amount). Thanks.

How do you write a negative dollar in parentheses?

For negative numbers, you can display the number with a leading red minus sign surrounded by parentheses or in red surrounded by parentheses.

How do you write a negative amount in a letter?

Per a vendor, for a negative number, the last character must be converted to a capital letter. For example, -123.45 should be sent over as 1234N.


2 Answers

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
like image 109
John Carter Avatar answered Sep 28 '22 16:09

John Carter


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);
like image 28
Johnny Dew Avatar answered Sep 28 '22 17:09

Johnny Dew