Php: Locale Aware Number Format

php number_format not using locale

The alternative is to use localeconv() to retrieve that information and use it in number_format(), something like:

$locale = localeconv(); 
echo number_format(
$number,
$locale['frac_digits'],
$locale['decimal_point'],
$locale['thousands_sep']
);

What does it mean by 'local settings aware' in printf() function of php

Depending on the locale you have on your server, the formatted string could be different. You can change the locale by using setlocale (you need to have the locale extension installed if you want it to work);

E.g:

setlocale(LC_ALL,'de_DE.utf8');
printf ('%F', 1.234); //this prints 1.234
printf ('%f', 1.234); //this prints 1,234

Format a number with grouped thousands

Use number_format():

number_format($number);

Print Currency Number Format in PHP

The easiest answer is number_format().

echo "$ ".number_format($value, 2);

If you want your application to be able to work with multiple currencies and locale-aware formatting (1.000,00 for some of us Europeans for example), it becomes a bit more complex.

There is money_format() but it doesn't work on Windows and relies on setlocale(), which is rubbish in my opinion, because it requires the installation of (arbitrarily named) locale packages on server side.

If you want to seriously internationalize your application, consider using a full-blown internationalization library like Zend Framework's Zend_Locale and Zend_Currency.

Number format with str_replace

Using BCMath extension of PHP directly.

Source code:

<?php
$num = bcmul('123.45', 100);
var_dump($num);

$num = bcmul('123.456', 100);
var_dump($num);

// The thrid parameter is used to set the number of digits after the decimal place in the result.
$num = bcmul('123.456', 100, 1);
var_dump($num);

$num = bcmul('123456.78', 100);
var_dump($num);

Output:

string(5) "12345"
string(5) "12345"
string(7) "12345.6"
string(8) "12345678"

For more information, see https://www.php.net/manual/en/function.bcmul.php

customize format number to flexible

Replace any character other than a digit with a blank in the first assignment made to $this->val.
i.e.

    public function number_word($in_val = 0, $in_currency0 = "", $in_currency1 = "") {    
//$this->val = preg_replace('/[^0-9]/', '', $in_val);
$this->val = str_replace(",", ".", preg_replace('/(\d+)\./', '$1', $in_val));
.
.
.
.
.

Edit: 1)Remove g flag from Regex
2) Added the str_replace and changed the regex to handle German and US/UK format

Arbitrary precision number formatting / money_format?

Cobbled together from the commenter-submitted functions on PHP's site here and here. Edited to work with arbitrary-precision parameters.

class format {
function money($format, $number)
{
// Takes plain-format, arbitrary-length decimal string (eg: '123456789123456789.123456')
// Returns localized monetary string, truncated at the hundredth value after the decimal point.
// (eg: $ 123,456,789,123,456,789.12)
$regex = '/%((?:[\^!\-]|\+|\(|\=.)*)([0-9]+)?'.
'(?:#([0-9]+))?(?:\.([0-9]+))?([in%])/';
if (setlocale(LC_MONETARY, 0) == 'C') {
setlocale(LC_MONETARY, '');
}
$locale = localeconv();
preg_match_all($regex, $format, $matches, PREG_SET_ORDER);
foreach ($matches as $fmatch) {
$value = (string) $number;
$flags = array(
'fillchar' => preg_match('/\=(.)/', $fmatch[1], $match) ?
$match[1] : ' ',
'nogroup' => preg_match('/\^/', $fmatch[1]) > 0,
'usesignal' => preg_match('/\+|\(/', $fmatch[1], $match) ?
$match[0] : '+',
'nosimbol' => preg_match('/\!/', $fmatch[1]) > 0,
'isleft' => preg_match('/\-/', $fmatch[1]) > 0
);
$width = trim($fmatch[2]) ? (int)$fmatch[2] : 0;
$left = trim($fmatch[3]) ? (int)$fmatch[3] : 0;
$right = trim($fmatch[4]) ? (int)$fmatch[4] : $locale['int_frac_digits'];
$conversion = $fmatch[5];

$positive = true;
if ($value[0] == '-') {
$positive = false;
$value = bcmul($value, '-1');
}
$letter = $positive ? 'p' : 'n';

$prefix = $suffix = $cprefix = $csuffix = $signal = '';

$signal = $positive ? $locale['positive_sign'] : $locale['negative_sign'];

if ($locale["{$letter}_sign_posn"] == 1 && $flags['usesignal'] == '+')
$prefix = $signal;
elseif ($locale["{$letter}_sign_posn"] == 2 && $flags['usesignal'] == '+')
$suffix = $signal;
elseif ($locale["{$letter}_sign_posn"] == 3 && $flags['usesignal'] == '+')
$cprefix = $signal;
elseif ($locale["{$letter}_sign_posn"] == 4 && $flags['usesignal'] == '+')
$csuffix = $signal;
elseif ($flags['usesignal'] == '(' || $locale["{$letter}_sign_posn"] == 0) {
$prefix = '(';
$suffix = ')';

}
if (!$flags['nosimbol']) {
$currency = $cprefix .
($conversion == 'i' ? $locale['int_curr_symbol'] : $locale['currency_symbol']) .
$csuffix;
} else {
$currency = '';
}
$space = $locale["{$letter}_sep_by_space"] ? ' ' : '';

$value = format::number($value, $right, $locale['mon_decimal_point'],
$flags['nogroup'] ? '' : $locale['mon_thousands_sep']);

$value = @explode($locale['mon_decimal_point'], $value);

$n = strlen($prefix) + strlen($currency) + strlen($value[0]);
if ($left > 0 && $left > $n) {
$value[0] = str_repeat($flags['fillchar'], $left - $n) . $value[0];
}
$value = implode($locale['mon_decimal_point'], $value);
if ($locale["{$letter}_cs_precedes"]) {
$value = $prefix . $currency . $space . $value . $suffix;
} else {
$value = $prefix . $value . $space . $currency . $suffix;
}
if ($width > 0) {
$value = str_pad($value, $width, $flags['fillchar'], $flags['isleft'] ?
STR_PAD_RIGHT : STR_PAD_LEFT);
}

$format = str_replace($fmatch[0], $value, $format);
}
return $format;
}

function number ($number , $decimals = 2 , $dec_point = '.' , $sep = ',', $group=3 ){
// Arbitrary-precision number formatting:
// Takes plain-format, arbitrary-length decimal string (eg: '123456789123456789.123456').
// Takes the same parameters as PHP's native number_format plus a flexible 'grouping' parameter.
// WARNINGS: Truncates -- does not round; not inherently locale-aware

$num = (string) $number;
if (strpos($num, '.')) $num = substr($num, 0, (strpos($num, '.') + 1 + $decimals)); // truncate
$num = explode('.',$num);
while (strlen($num[0]) % $group) $num[0]= ' '.$num[0];
$num[0] = str_split($num[0],$group);
$num[0] = join($sep[0],$num[0]);
$num[0] = trim($num[0]);
$num = join($dec_point[0],$num);

return $num;
}
}

Tests:

 setlocale(LC_MONETARY, 'en_ZW'); // pick your favorite hyperinflated currency
$string = '123456789123456789.123456';

echo "original string: " .
$string . "<br>";
// 123456789123456789.123456
echo "float cast - " .
((float) $string) . "<br>";
// 1.23456789123E+17
echo "number_format original: " .
number_format($string, 4) . "<br>";
// 123,456,789,123,456,768.0000
echo "number_format new: " .
format::number($string, 4) . "<br>";
// 123,456,789,123,456,789.1234
echo "money_format original: " .
money_format('%n', $string) . "<br>";
// Z$ 123,456,789,123,456,784.00
echo "money_format new: " .
format::money('%n',$string) . "<br>";
// Z$ 123,456,789,123,456,789.12

Formatting DateTime object, respecting Locale::getDefault()

That's because format does not pay attention to locale. You should use strftime instead.

For example:

setlocale(LC_TIME, "de_DE"); //only necessary if the locale isn't already set
$formatted_time = strftime("%a %e.%l.%Y", $mytime->getTimestamp())


Related Topics



Leave a reply



Submit