PHP NumberFormatter: Decimal Digits bug - SOLVED

46 Views Asked by At

I'm new to using NumberFormatter (PHP) and right at the beginning I encountered a strange behavior that I consider a bug. I have searched for a solution but have not found one.

I want to present prices according to customer conventions (correct decimal and thousands separators and correct currency marking), and I always want to present prices without the decimal part. When I use the setAttribute(NumberFormatter::FRACTION_DIGITS, 0) and/or setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 0) settings, this only works for the currency intended for payments in that country. For prices in other currencies, it ignores the number of decimal places parameter.

Am I doing something wrong? How to force the given setting for all outputs?

Example code:

<?php
$val = 1234567.891234567890000;
$lngs = array("de_DE", "de_CH", "fr_CH", "nl_NL", "en_US", "en_GB", "cs_CZ");
$crncs = array("EUR", "CZK", "USD", "GBP", "CHF");

echo "<table border='1' style='width:auto;'>";
foreach($lngs as $lng) {
    echo "<tr><th colspan='3' style='text-align: center;'>$lng</th>";
    foreach ($crncs as $currency) {
        $fmt = new NumberFormatter($lng, NumberFormatter::CURRENCY );
        $fmt->setAttribute(NumberFormatter::FRACTION_DIGITS, 0); // this will be ignored everywhere except in a direct currency-language match
        echo "<tr style='text-align: right;'><td>" . $currency . "</td><td>" . $fmt->formatCurrency($val, $currency) . "</td><td>" . $fmt->formatCurrency(-1 * $val, $currency) . "</td></tr>";
    }
}
echo "</table>";

working example here

my output:

de_DE
EUR 1.234.568 € -1.234.568 €
CZK 1.234.567,89 CZK    -1.234.567,89 CZK
USD 1.234.567,89 $  -1.234.567,89 $
GBP 1.234.567,89 £  -1.234.567,89 £
CHF 1.234.567,90 CHF    -1.234.567,90 CHF
de_CH
EUR € 1'234'567.89  €-1'234'567.89
CZK CZK 1'234'567.89    CZK-1'234'567.89
USD $ 1'234'567.89  $-1'234'567.89
GBP £ 1'234'567.89  £-1'234'567.89
CHF CHF 1'234'568   CHF-1'234'568
fr_CH
EUR € 1'234'567.89  €-1'234'567.89
CZK CZK 1'234'567.89    CZK-1'234'567.89
USD $US 1'234'567.89    $US-1'234'567.89
GBP £UK 1'234'567.89    £UK-1'234'567.89
CHF CHF 1'234'568   CHF-1'234'568
nl_NL
EUR € 1.234.568 € 1.234.568-
CZK CZK 1.234.567,89    CZK 1.234.567,89-
USD US$ 1.234.567,89    US$ 1.234.567,89-
GBP £ 1.234.567,89  £ 1.234.567,89-
CHF CHF 1.234.567,90    CHF 1.234.567,90-
en_US
EUR €1,234,567.89   (€1,234,567.89)
CZK CZK1,234,567.89 (CZK1,234,567.89)
USD $1,234,568  ($1,234,568)
GBP £1,234,567.89   (£1,234,567.89)
CHF CHF1,234,567.90 (CHF1,234,567.90)
en_GB
EUR €1,234,567.89   -€1,234,567.89
CZK CZK1,234,567.89 -CZK1,234,567.89
USD $1,234,567.89   -$1,234,567.89
GBP £1,234,568  -£1,234,568
CHF CHF1,234,567.90 -CHF1,234,567.90
cs_CZ
EUR 1 234 567,89 €  -1 234 567,89 €
CZK 1 234 568 Kč    -1 234 568 Kč
USD 1 234 567,89 US$    -1 234 567,89 US$
GBP 1 234 567,89 £  -1 234 567,89 £
CHF 1 234 567,90 CHF    -1 234 567,90 CHF

SOLUTION:

After further searching and elaboring I FOUND THE SOLUTION.

Before setting the number of decimal places, you still need to explicitly specify the currency:

$fmt->setTextAttribute(NumberFormatter::CURRENCY_CODE, $currency);

The function code is then:

<?php
$val = 1234567.891234567890000;
$lngs = array("de_DE", "de_CH", "fr_CH", "nl_NL", "en_US", "en_GB", "cs_CZ");
$crncs = array("EUR", "CZK", "USD", "GBP", "CHF");

echo "<table border='1' style='width:auto;'>";
foreach($lngs as $lng) {
    echo "<tr><th colspan='3' style='text-align: center;'>$lng</th>";
    foreach ($crncs as $currency) {
        $fmt = new NumberFormatter($lng, NumberFormatter::CURRENCY );

        // new line of code that solves the problem
        $fmt->setTextAttribute(NumberFormatter::CURRENCY_CODE, $currency);

        $fmt->setAttribute(NumberFormatter::FRACTION_DIGITS, 0);
        echo "<tr style='text-align: right;'><td>" . $currency . "</td><td>" . $fmt->formatCurrency($val, $currency) . "</td><td>" . $fmt->formatCurrency(-1 * $val, $currency) . "</td></tr>";
    }
}
echo "</table>";
0

There are 0 best solutions below