Skip to content

Commit

Permalink
working on number class
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorotwell committed Nov 17, 2023
1 parent 59c509b commit 8ab2184
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 17 deletions.
39 changes: 27 additions & 12 deletions src/Illuminate/Support/Number.php
Expand Up @@ -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);
}

Expand All @@ -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);
}
Expand All @@ -56,45 +69,47 @@ 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);
}

/**
* Convert the given number to its file size equivalent.
*
* @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'];

for ($i = 0; ($bytes / 1024) > 0.9 && ($i < count($units) - 1); $i++) {
$bytes /= 1024;
}

return sprintf('%s %s', number_format($bytes, $precision), $units[$i]);
return sprintf('%s %s', static::format($bytes, $precision, $maxPrecision), $units[$i]);
}

/**
* Convert the number to its human readable equivalent.
*
* @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',
Expand All @@ -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] ?? ''));
}

/**
Expand Down
29 changes: 24 additions & 5 deletions tests/Support/SupportNumberTest.php
Expand Up @@ -17,13 +17,19 @@ 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));
$this->assertSame('-10', Number::format(-10));
$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));
Expand All @@ -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()
Expand All @@ -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));
Expand All @@ -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));
}
Expand Down Expand Up @@ -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));
Expand All @@ -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));
Expand Down Expand Up @@ -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));
}
Expand Down

0 comments on commit 8ab2184

Please sign in to comment.