Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NumberFormatter to leave always 2 digits behind floating point

I have ended up with a little bit of an overkill here, but I just cannot seem how to nail it:

$formatter = new NumberFormatter('lv_LV', NumberFormatter::DECIMAL);

$formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
$formatter->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, 2);
$formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 2);
$formatter->setAttribute(NumberFormatter::DECIMAL_ALWAYS_SHOWN, 2);

What I am trying to achieve here is:

+-------+--------+----------+-------+
| INPUT | ACTUAL | EXPECTED | VALID |
+-------+--------+----------+-------+
|  5,77 |   5.77 |     5.77 | YES   |
|  5,20 |    5.2 |     5.20 | NO    |
|  5,00 |      5 |     5.00 | NO    |
|     0 |      0 |     0.00 | NO    |
+-------+--------+----------+-------+

In short, I always want 2 digits behind the floating point.

How do I achieve this with PHP's NumberFormatter?

like image 614
tomsseisums Avatar asked Feb 02 '26 04:02

tomsseisums


1 Answers

The accepted answer is correct, I am looking to provide clarification as to why the OP was not receiving the expected results with NumberFormatter.

NumberFormatter::parse will output a float and accepts a string argument in the specified locale format. Parse however does not format the output. It is the equivalent of performing echo (float) '5.20'; //(float) 5.2

NumberFormatter::format will output a string in the specified locale format and accepts an integer or float argument. It is the equivalent of performing echo number_format(5.2, 2); //(string) "5.20" However number_format uses default values as the fraction and thousands separators and they would need to be changed based on desired display rules.

NumberFormatter requires that you call the parse method prior to calling the format method, for it to convert the locale specific string value to the integer or float value equivalent and have a separate NumberFormatter for your desired output.

Example https://3v4l.org/HRnQN

$lv = new \NumberFormatter('lv', \NumberFormatter::DECIMAL);
$lv->setAttribute($input::FRACTION_DIGITS, 2); //applies rounding during format

$en = new \NumberFormatter('en', \NumberFormatter::DECIMAL);
$en->setAttribute($output::FRACTION_DIGITS, 2); //applies rounding during format

foreach (['5,77', '5,20', '5,2', '5,00', '5', '0'] as $value) {
   $parsed = $lv->parse($value);
   var_dump($parsed); //convert locale string to float value
   var_dump($en->format($parsed)); //convert float to locale string
   var_dump($lv->format($parsed)); //convert float to locale string
   echo "<br/>\n";
}

$lv::parse($value)

+-------+--------+----------+-------+
| Value |  Parse | EXPECTED | VALID |
+-------+--------+----------+-------+
|  5,77 |   5.77 |     5.77 | YES   |
|  5,20 |    5.2 |      5.2 | YES   |
|   5,2 |    5.2 |      5.2 | YES   |
|  5,00 |      5 |        5 | YES   |
|     5 |      5 |        5 | YES   |
|     0 |      0 |        0 | YES   |
+-------+--------+----------+-------+

$en::format($parsed)

+-------+--------+----------+-------+
| Value | Format | EXPECTED | VALID |
+-------+--------+----------+-------+
|  5,77 |   5.77 |     5.77 | YES   |
|  5,20 |   5.20 |     5.20 | YES   |
|   5,2 |   5.20 |     5.20 | YES   |
|  5,00 |   5.00 |     5.00 | YES   |
|     5 |   5.00 |     5.00 | YES   |
|     0 |   0.00 |     0.00 | YES   |
+-------+--------+----------+-------+

$lv::format($parsed)

+-------+--------+----------+-------+
| Value | Format | EXPECTED | VALID |
+-------+--------+----------+-------+
|  5,77 |   5,77 |     5,77 | YES   |
|  5,20 |   5,20 |     5,20 | YES   |
|   5,2 |   5,20 |     5,20 | YES   |
|  5,00 |   5,00 |     5,00 | YES   |
|     5 |   5,00 |     5,00 | YES   |
|     0 |   0,00 |     0,00 | YES   |
+-------+--------+----------+-------+
like image 139
Will B. Avatar answered Feb 03 '26 20:02

Will B.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!