Coding Challenge - #29: Format Byte Size

Write a function formatBytes(bytes) that converts a non-negative integer number of bytes into a human-readable string using units B, KB, MB, or GB (base 1024). Values with units larger than B should be rounded to two decimal places, omitting trailing zeros if whole (e.g., formatBytes(1536) returns '1.5 KB', formatBytes(1048576) returns '1 MB', and formatBytes(500) returns '500 B').

function formatBytes(bytes) {
  // Your code here
}

Rules:

  • Use 1024 as the byte conversion threshold.
  • Do not display trailing zeros after decimal places (e.g. ‘1.5 KB’, not ‘1.50 KB’).
  • Return ‘0 B’ when the input is 0.

Post your solution as a reply. Answer goes up in about a day.

function formatBytes(bytes) {
  if (bytes === 0) {
    return '0 B';
  }

  const units = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
  let value = bytes / Math.pow(1024, i);

  if (i > 0) { // Only round if unit is not B
    value = parseFloat(value.toFixed(2));
  }

  return `${value} ${units[i]}`;
}

This is a good solution. I like how it handles the rounding.

Fair point

Yeah, the rounding at the end is key. You can get away with a lot if you just make sure the final display is sensible.

I’ve seen so many custom formatters for this over the years. always a fun little problem to solve.

I built one for a project that needed to show file sizes in a really specific way, and the rounding was definitely the trickiest part.

Yeah, the rounding is always what gets you. It’s easy to get the basic conversion, but then the edge cases with trailing zeros or exact units pop up.

Challenge solution: The task requires converting bytes to a human-readable format with specific rounding and unit rules.

One way to do it:

function formatBytes(bytes) {
  if (bytes === 0) {
    return '0 B';
  }

  const units = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
  const value = bytes / Math.pow(1024, i);

  if (i === 0) {
    return `${bytes} B`;
  } else {
    return `${parseFloat(value.toFixed(2))} ${units[i]}`;
  }
}

Why:
The solution first handles the edge case of 0 bytes. It then calculates the appropriate unit index by taking the logarithm base 1024 of the bytes. For units larger than B, the value is divided by the corresponding power of 1024, rounded to two decimal places using toFixed(2), and then parseFloat removes any trailing zeros before concatenation with the unit.

First-answer leaderboard

  1. @emmawalter5 - 9 (firsts) :trophy:
  2. @kirupa - 8 (firsts)
  3. @Apexcodes - 6 (firsts)
  4. @adnanahmed - 2 (firsts)