Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Intl.NumberFormat without rounding

I'm using Intl.NumberFormat to format numbers:

const formatter = new Intl.NumberFormat('en-US', {
    minimumFractionDigits: 1,
    maximumFractionDigits: 4,
    minimumSignificantDigits: 1,
    maximumSignificantDigits: 4
  })

formatter.format(0.99999) // results: '1'. desired result: '0.9999'
formatter.format(0.006393555) // results: '0.006394'. desired result: '0.006393'
formatter.format(0.9972620384752073) // results: '0.9973'. desired result: '0.9972'
formatter.format(12345.67) // results: '12,350'. desired result: '12,345.67'
formatter.format(200001) // results: '200,000'. desired result: '200,001'

As you can see the numbers are being rounded automatically, which is undesirable behavior in my case.

Is there a way to tell the formatter not to round? I Didn't found any option or combination of options to achieve that.

like image 495
baba-dev Avatar asked Oct 13 '20 07:10

baba-dev


People also ask

What is Intl NumberFormat?

The Intl. NumberFormat() object enables language-sensitive number formatting. We can use this to convert currency, numbers, percentages, units, and other notation into formatted strings. This is particularly useful in eCommerce applications, with examples like displaying an item price or recipt printing.

How to round up decimals?

There are certain rules to follow when rounding a decimal number. Put simply, if the last digit is less than 5, round the previous digit down. However, if it's 5 or more than you should round the previous digit up. So, if the number you are about to round is followed by 5, 6, 7, 8, 9 round the number up.

What is Maximumsignificantdigits?

The maximum number of significant digits for the number formatter.

How do you format numbers in JavaScript?

JavaScript numbers can be formatted in different ways like commas, currency, etc. You can use the toFixed() method to format the number with decimal points, and the toLocaleString() method to format the number with commas and Intl. NumberFormat() method to format the number with currency.


2 Answers

NumberFormat will always round up, but you can play around this one extra function.

function roundDownSignificantDigits(number, decimals) {
  let significantDigits = (parseInt(number.toExponential().split('e-')[1])) || 0;
  let decimalsUpdated = (decimals || 0) +  significantDigits - 1;
  decimals = Math.min(decimalsUpdated, number.toString().length);

  return (Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals));
}

and then

const formatter = new Intl.NumberFormat('en-US', {
  minimumFractionDigits: 1,
  maximumFractionDigits: 4,
  minimumSignificantDigits: 1,
  maximumSignificantDigits: 4
})

result:

formatter.format(roundDownSignificantDigits(0.99999,4)); // "0.9999"
formatter.format(roundDownSignificantDigits(0.006393555,4)); // "0.006393"
formatter.format(roundDownSignificantDigits(0.9972620384752073,4)); // "0.9972"
like image 172
Code'as Avatar answered Oct 18 '22 18:10

Code'as


I don't think this is possible with current spec and there are few proposals for the new spec, but you can still use formatToParts method and add custom function to format number parts as you wish.

For your first use case it could look something like:

const trauncateFractionAndFormat = (parts, digits) => {
  return parts.map(({ type, value }) => {
    if (type !== 'fraction' || !value || value.length < digits) {
      return value;
    }
    
    let retVal = "";
    for (let idx = 0, counter = 0; idx < value.length && counter < digits; idx++) {
      if (value[idx] !== '0') {
        counter++;
      }
      retVal += value[idx];
    }
    return retVal;
  }).reduce((string, part) => string + part);
};
const formatter = new Intl.NumberFormat('en-US', {
  minimumFractionDigits: 0,
  maximumFractionDigits: 20
})

console.log(trauncateFractionAndFormat(formatter.formatToParts(0.99999), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(0.006393555), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(0.9972620384752073), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(12345.67), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(20001), 4));
like image 30
Dipen Shah Avatar answered Oct 18 '22 19:10

Dipen Shah