diff --git a/src/Illuminate/Support/Number.php b/src/Illuminate/Support/Number.php index 49feddf71eeb..cca9795ff0e6 100644 --- a/src/Illuminate/Support/Number.php +++ b/src/Illuminate/Support/Number.php @@ -21,15 +21,23 @@ class Number * Format the given number according to the current locale. * * @param int|float $number + * @param int|null $precision + * @param int|null $maxPrecision * @param ?string $locale * @return string|false */ - public static function format(int|float $number, ?string $locale = null) + public static function format(int|float $number, ?int $precision = null, ?int $maxPrecision = null, ?string $locale = null) { static::ensureIntlExtensionIsInstalled(); $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::DECIMAL); + if (! is_null($maxPrecision)) { + $formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $maxPrecision); + } elseif (! is_null($precision)) { + $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $precision); + } + return $formatter->format($number); } @@ -38,16 +46,21 @@ public static function format(int|float $number, ?string $locale = null) * * @param int|float $number * @param int $precision + * @param int|null $maxPrecision * @param ?string $locale * @return string|false */ - public static function percentage(int|float $number, int $precision = 0, ?string $locale = null) + public static function percentage(int|float $number, int $precision = 0, ?int $maxPrecision = null, ?string $locale = null) { static::ensureIntlExtensionIsInstalled(); $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::PERCENT); - $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $precision); + if (! is_null($maxPrecision)) { + $formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $maxPrecision); + } else { + $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $precision); + } return $formatter->format($number / 100); } @@ -56,17 +69,17 @@ public static function percentage(int|float $number, int $precision = 0, ?string * Convert the given number to its currency equivalent. * * @param int|float $number - * @param string $currency + * @param string $in * @param ?string $locale * @return string|false */ - public static function currency(int|float $number, string $currency = 'USD', ?string $locale = null) + public static function currency(int|float $number, string $in = 'USD', ?string $locale = null) { static::ensureIntlExtensionIsInstalled(); $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::CURRENCY); - return $formatter->formatCurrency($number, $currency); + return $formatter->formatCurrency($number, $in); } /** @@ -74,9 +87,10 @@ public static function currency(int|float $number, string $currency = 'USD', ?st * * @param int|float $bytes * @param int $precision + * @param int|null $maxPrecision * @return string */ - public static function fileSize(int|float $bytes, int $precision = 0) + public static function fileSize(int|float $bytes, int $precision = 0, ?int $maxPrecision = null) { $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; @@ -84,7 +98,7 @@ public static function fileSize(int|float $bytes, int $precision = 0) $bytes /= 1024; } - return sprintf('%s %s', number_format($bytes, $precision), $units[$i]); + return sprintf('%s %s', static::format($bytes, $precision, $maxPrecision), $units[$i]); } /** @@ -92,9 +106,10 @@ public static function fileSize(int|float $bytes, int $precision = 0) * * @param int $number * @param int $precision + * @param int|null $maxPrecision * @return string */ - public static function forHumans(int|float $number, int $precision = 0) + public static function forHumans(int|float $number, int $precision = 0, ?int $maxPrecision = null) { $units = [ 3 => 'thousand', @@ -108,16 +123,16 @@ public static function forHumans(int|float $number, int $precision = 0) case $number === 0: return '0'; case $number < 0: - return sprintf('-%s', static::forHumans(abs($number), $precision)); + return sprintf('-%s', static::forHumans(abs($number), $precision, $maxPrecision)); case $number >= 1e15: - return sprintf('%s quadrillion', static::forHumans($number / 1e15, $precision)); + return sprintf('%s quadrillion', static::forHumans($number / 1e15, $precision, $maxPrecision)); } $numberExponent = floor(log10($number)); $displayExponent = $numberExponent - ($numberExponent % 3); $number /= pow(10, $displayExponent); - return trim(sprintf('%s %s', number_format($number, $precision), $units[$displayExponent])); + return trim(sprintf('%s %s', static::format($number, $precision, $maxPrecision), $units[$displayExponent] ?? '')); } /** diff --git a/tests/Support/SupportNumberTest.php b/tests/Support/SupportNumberTest.php index 73787bae682a..58470731e70b 100644 --- a/tests/Support/SupportNumberTest.php +++ b/tests/Support/SupportNumberTest.php @@ -17,6 +17,10 @@ public function testFormat() $this->assertSame('25', Number::format(25)); $this->assertSame('100', Number::format(100)); $this->assertSame('100,000', Number::format(100000)); + $this->assertSame('100,000.00', Number::format(100000, precision: 2)); + $this->assertSame('100,000.12', Number::format(100000.123, precision: 2)); + $this->assertSame('100,000.123', Number::format(100000.1234, maxPrecision: 3)); + $this->assertSame('100,000.124', Number::format(100000.1236, maxPrecision: 3)); $this->assertSame('123,456,789', Number::format(123456789)); $this->assertSame('-1', Number::format(-1)); @@ -24,6 +28,8 @@ public function testFormat() $this->assertSame('-25', Number::format(-25)); $this->assertSame('0.2', Number::format(0.2)); + $this->assertSame('0.20', Number::format(0.2, precision: 2)); + $this->assertSame('0.123', Number::format(0.1234, maxPrecision: 3)); $this->assertSame('1.23', Number::format(1.23)); $this->assertSame('-1.23', Number::format(-1.23)); $this->assertSame('123.456', Number::format(123.456)); @@ -36,11 +42,11 @@ public function testFormatWithDifferentLocale() { $this->needsIntlExtension(); - $this->assertSame('123,456,789', Number::format(123456789, 'en')); - $this->assertSame('123.456.789', Number::format(123456789, 'de')); - $this->assertSame('123 456 789', Number::format(123456789, 'fr')); - $this->assertSame('123 456 789', Number::format(123456789, 'ru')); - $this->assertSame('123 456 789', Number::format(123456789, 'sv')); + $this->assertSame('123,456,789', Number::format(123456789, locale: 'en')); + $this->assertSame('123.456.789', Number::format(123456789, locale: 'de')); + $this->assertSame('123 456 789', Number::format(123456789, locale: 'fr')); + $this->assertSame('123 456 789', Number::format(123456789, locale: 'ru')); + $this->assertSame('123 456 789', Number::format(123456789, locale: 'sv')); } public function testFormatWithAppLocale() @@ -66,6 +72,7 @@ public function testToPercent() $this->assertSame('10.00%', Number::percentage(10, precision: 2)); $this->assertSame('100%', Number::percentage(100)); $this->assertSame('100.00%', Number::percentage(100, precision: 2)); + $this->assertSame('100.123%', Number::percentage(100.1234, maxPrecision: 3)); $this->assertSame('300%', Number::percentage(300)); $this->assertSame('1,000%', Number::percentage(1000)); @@ -74,6 +81,7 @@ public function testToPercent() $this->assertSame('1.75%', Number::percentage(1.75, precision: 2)); $this->assertSame('1.750%', Number::percentage(1.75, precision: 3)); $this->assertSame('0%', Number::percentage(0.12345)); + $this->assertSame('0.00%', Number::percentage(0, precision: 2)); $this->assertSame('0.12%', Number::percentage(0.12345, precision: 2)); $this->assertSame('0.1235%', Number::percentage(0.12345, precision: 4)); } @@ -111,11 +119,13 @@ public function testToCurrencyWithDifferentLocale() public function testBytesToHuman() { $this->assertSame('0 B', Number::fileSize(0)); + $this->assertSame('0.00 B', Number::fileSize(0, precision: 2)); $this->assertSame('1 B', Number::fileSize(1)); $this->assertSame('1 KB', Number::fileSize(1024)); $this->assertSame('2 KB', Number::fileSize(2048)); $this->assertSame('2.00 KB', Number::fileSize(2048, precision: 2)); $this->assertSame('1.23 KB', Number::fileSize(1264, precision: 2)); + $this->assertSame('1.234 KB', Number::fileSize(1264.12345, maxPrecision: 3)); $this->assertSame('1.234 KB', Number::fileSize(1264, 3)); $this->assertSame('5 GB', Number::fileSize(1024 * 1024 * 1024 * 5)); $this->assertSame('10 TB', Number::fileSize((1024 ** 4) * 10)); @@ -128,9 +138,14 @@ public function testBytesToHuman() public function testToHuman() { $this->assertSame('1', Number::forHumans(1)); + $this->assertSame('1.00', Number::forHumans(1, precision: 2)); $this->assertSame('10', Number::forHumans(10)); $this->assertSame('100', Number::forHumans(100)); $this->assertSame('1 thousand', Number::forHumans(1000)); + $this->assertSame('1.00 thousand', Number::forHumans(1000, precision: 2)); + $this->assertSame('1 thousand', Number::forHumans(1000, maxPrecision: 2)); + $this->assertSame('1 thousand', Number::forHumans(1230)); + $this->assertSame('1.2 thousand', Number::forHumans(1230, maxPrecision: 1)); $this->assertSame('1 million', Number::forHumans(1000000)); $this->assertSame('1 billion', Number::forHumans(1000000000)); $this->assertSame('1 trillion', Number::forHumans(1000000000000)); @@ -159,12 +174,16 @@ public function testToHuman() $this->assertSame('0', Number::forHumans(0)); $this->assertSame('-1', Number::forHumans(-1)); + $this->assertSame('-1.00', Number::forHumans(-1, precision: 2)); $this->assertSame('-10', Number::forHumans(-10)); $this->assertSame('-100', Number::forHumans(-100)); $this->assertSame('-1 thousand', Number::forHumans(-1000)); + $this->assertSame('-1.23 thousand', Number::forHumans(-1234, precision: 2)); + $this->assertSame('-1.2 thousand', Number::forHumans(-1234, maxPrecision: 1)); $this->assertSame('-1 million', Number::forHumans(-1000000)); $this->assertSame('-1 billion', Number::forHumans(-1000000000)); $this->assertSame('-1 trillion', Number::forHumans(-1000000000000)); + $this->assertSame('-1.1 trillion', Number::forHumans(-1100000000000, maxPrecision: 1)); $this->assertSame('-1 quadrillion', Number::forHumans(-1000000000000000)); $this->assertSame('-1 thousand quadrillion', Number::forHumans(-1000000000000000000)); }