使用 Intl.NumberFormat 而不四舍五入

Use Intl.NumberFormat without rounding

我正在使用 Intl.NumberFormat 格式化数字:

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'

如您所见,数字会自动四舍五入,这对我来说是不受欢迎的行为。

有没有办法告诉格式化程序不要四舍五入? 我没有 found any option 或选项组合来实现它。

NumberFormat 将始终向上舍入,但您可以使用这个额外的功能。

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));
}

然后

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

结果:

formatter.format(roundDownSignificantDigits(0.99999,4)); // "0.9999"
formatter.format(roundDownSignificantDigits(0.006393555,4)); // "0.006393"
formatter.format(roundDownSignificantDigits(0.9972620384752073,4)); // "0.9972"

我认为这在当前规范中是不可能的,并且有 few proposals for the new spec,但您仍然可以使用 formatToParts 方法并添加自定义函数以根据需要格式化数字部分。

对于您的第一个用例,它可能类似于:

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));

我可以使用 formatToParts 获取它。如果需要,您还可以使用一些 javascript 数组函数技巧来分隔小数部分。

export const formatNumberWithoutDecimals = (price) =>
  new Intl.NumberFormat(i18n.language, {
    minimumFractionDigits: 2,
  }).formatToParts(price).reduce((result, part) => (part.type !== "decimal" && part.type !== "fraction") ? result + part.value : result, "");