How To Handle Decimal Number?

Hi

I have a form where the user can input some money quantities. If they input a number like 30.5 it works, but if they use a comma (,) instead of the dot (.) it doesn’t work and the decimals are saved as 0.

I’ve tried this in teh beforeSave() method:


$this->price = Yii::app()->numberFormatter->formatCurrency($this->price, 'EUR');

If I input 30,5 it will save “30,00 €” as a string. If I input 30.5 it will save “30,50 €”. So it changes the dot to a comma, but if I input a comma it doesn’t work.

Is there any way to solve this?




$this->price = Yii::app()->numberFormatter->formatCurrency(strtr($this->price,array(','=>'.')), 'EUR');



:)

It works, thanks :)

Another question.

That value is saved in my DB as a string like "30,50 €". How can I parse it into a float number so I can make operations with it?

I wouldn’t care if I had to save it in the DB as a floating number without the “€”. I’ll need it for future projects.

Don’t do monetary calculations on floats! Just use the smaller unit, like cents.

I parse monetary input using a following filter in my validation rules:




    public static function str2dec($value, $precision = 2) {

        $value = preg_replace('/[^\d,\.]+/', '', $value);

        if ($value === '') return null;

        if (($seppos = strpos($value,',')) === false && ($seppos = strpos($value,'.')) === false) {

            $value = $value.str_pad('', $precision, '0');

        } else {

            $distance = strlen($value) - $seppos;

            if ($distance > $precision) {

                $value = substr($value, 0, $seppos + $precision + 1);

            } else {

                do {

                    $value .= '0';

                } while ($distance !== $precision-- && $precision > 0);

            }

            $value = str_replace(array(',','.'), '', $value);

        }

        return min(max((int)$value, -2147483648), 2147483647);

    }



This code strips all non digit and non comma (dot) chars and trims too many fraction digits or pads it with zeros to the specified precision, then casts it to int. So it handles cases such as:

  • 30 -> 3000

  • 30,1 -> 3010

  • 30,23 -> 3023

  • 30,234 -> 3023

The drawback is I really need to pay attention not to call validation twice, because on the second run the value will be treated as without fractional part and multiplied by 100.

The advantage is that I always have those numbers stored as integers, ready for some fast and precise calculations.

you need to store it as float(double) in your model (and hence in database) and use Yii::app()->numberFormatter->formatCurrency() only to display that value (in views, grids, etc)

another thing is what nineichnick pointed out. you should use something like bcmath php module (http://php.net/manual/pl/book.bc.php) for currency operators so you do not loose precision.

Thank you both for the tips. I’ll check it out.