Skip to content

Instantly share code, notes, and snippets.

@lanqy
Created March 19, 2013 03:05
Show Gist options
  • Select an option

  • Save lanqy/5193417 to your computer and use it in GitHub Desktop.

Select an option

Save lanqy/5193417 to your computer and use it in GitHub Desktop.
JavaScript To Convert Bytes To MB, KB, Etc
// from http://scratch99.com/web-development/javascript/convert-bytes-to-mb-kb/
function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (bytes == 0) return 'n/a';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
if (i == 0) return bytes + ' ' + sizes[i];
return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
};
@zackster

zackster commented Apr 14, 2020

Copy link
Copy Markdown

A little bit of code for people who want the reverse.
Basically adapted this from https://stackoverflow.com/a/31625253/104461

function printpower (n, base, power) {
  if (base === 2) { // 1 << power is approx 10x faster than Math.pow(2, power) 
    console.log(n * (1 << power))
  } else {
    console.log(n * Math.pow(base, power))
  }
}

const humanReadable = '86 MB'

const [n, abbreviation] = humanReadable.split(/\s+/)
if (abbreviation) {
  if (/K(iB)?$/.test(abbreviation)) {
    printpower(n, 2, 10)
  } else if (/M(iB)?$/.test(abbreviation)) {
    printpower(n, 2, 20)
  } else if (/G(iB)?$/.test(abbreviation)) {
    printpower(n, 2, 30)
  } else if (/T(iB)?$/.test(abbreviation)) {
    printpower(n, 2, 40)
  } else if (/KB$/.test(abbreviation)) {
    printpower(n, 10, 3)
  } else if (/MB$/.test(abbreviation)) {
    printpower(n, 10, 6)
  } else if (/GB$/.test(abbreviation)) {
    printpower(n, 10, 9)
  } else if (/TB$/.test(abbreviation)) {
    printpower(n, 10, 12)
  }
} else {
  console.log(n)
}

Edit: the if statement is probably pretty expensive, and so are the Regular Expressions (at a minimum, should be compiled once as const variables), so there is room for incremental optimization!

@tobiasalbirosa

Copy link
Copy Markdown

Thanks all of you

@ahmnouira

Copy link
Copy Markdown

TypeScript version:

export function bytesToSize(bytes: number): string {
  const sizes: string[] = ['Bytes', 'KB', 'MB', 'GB', 'TB']
  if (bytes === 0) return 'n/a'
  const i: number = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)).toString())
  if (i === 0) return `${bytes} ${sizes[i]}`
  return `${(bytes / Math.pow(1024, i)).toFixed(1)} ${sizes[i]}`
}

@trankov

trankov commented Jul 14, 2021

Copy link
Copy Markdown

Strength and power of open source community. I'm shocked and impressed. Thanks to all, guys.

@denik1981

denik1981 commented Aug 27, 2021

Copy link
Copy Markdown
function bytesToSize(bytes) {
  const units = ["byte", "kilobyte", "megabyte", "terabyte", "petabyte"];
  const unit = Math.floor(Math.log(bytes) / Math.log(1024));
  return new Intl.NumberFormat("en", {style: "unit", unit: units[unit]}).format(bytes / 1024 ** unit);
}

@rmorlok

rmorlok commented Jul 8, 2022

Copy link
Copy Markdown

To expand on the typescript version, I don't think the parseInt(...) is required. Also, in the unlikely case that you exceed 999.9 TB, you end up in xxx.x undefined territory.

Here is a fixed Typescript version:

export function bytesToSize(bytes: number): string {
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
  if (bytes === 0) return 'n/a';
  const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), sizes.length - 1);
  if (i === 0) return `${bytes} ${sizes[i]}`;
  return `${(bytes / (1024 ** i)).toFixed(1)} ${sizes[i]}`;
}

With Jest spec:

describe('bytesToSize', () => {
  test.each([
    [0, 'n/a'],
    [1, '1 Bytes'],
    [2000, '2.0 KB'],
    [30000, '29.3 KB'],
    [400000, '390.6 KB'],
    [5000000, '4.8 MB'],
    [60000000, '57.2 MB'],
    [700000000, '667.6 MB'],
    [8000000000, '7.5 GB'],
    [90000000000, '83.8 GB'],
    [100000000000, '93.1 GB'],
    [1100000000000, '1.0 TB'],
    [12000000000000, '10.9 TB'],
    [130000000000000, '118.2 TB'],
    [1400000000000000, '1273.3 TB'],
    [15000000000000000, '13642.4 TB'],
  ])('.bytesToSize(%p)', (
    val: number,
    expected: string,
  ) => {
    expect(
      bytesToSize(val),
    ).toBe(expected);
  });
});

@Dymerz

Dymerz commented Nov 23, 2022

Copy link
Copy Markdown

Using the Intl.NumberFormat for local friendly conversions

export function bytesToSize(bytes: number): string {
  const units = ['byte', 'kilobyte', 'megabyte', 'gigabyte', 'terabyte'];

  const navigatorLocal = navigator.languages && navigator.languages.length >= 0 ? navigator.languages[0] : 'en-US'
  const unitIndex      = Math.max(0, Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1));

  return Intl.NumberFormat(navigatorLocal, {
    style: 'unit',
    unit : units[unitIndex]
  }).format(bytes / (1024 ** unitIndex))
}

@HaukeHa

HaukeHa commented Sep 28, 2023

Copy link
Copy Markdown

The sizes should be named Mebibyte (MiB), Gibibyte (GiB) etc if you use 1024 for the calculation.

Or if you want to calculate Megabyte, Gigabyte etc. replace the '1024' in the code by '1000'.

@gynekolog

gynekolog commented Nov 9, 2023

Copy link
Copy Markdown

@HaukeHa Thank you for noticing 👍 

I use the following code:

export function convertBytes(bytes: number, options: { useBinaryUnits?: boolean; decimals?: number } = {}): string {
  const { useBinaryUnits = false, decimals = 2 } = options;

  if (decimals < 0) {
    throw new Error(`Invalid decimals ${decimals}`);
  }

  const base = useBinaryUnits ? 1024 : 1000;
  const units = useBinaryUnits
    ? ["Bytes", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]
    : ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];

  const i = Math.floor(Math.log(bytes) / Math.log(base));

  return `${(bytes / Math.pow(base, i)).toFixed(decimals)} ${units[i]}`;
}

and basic tests:

import { describe, expect } from "vitest";
import { convertBytes } from "./bytes";

describe("convertBytes", () => {
  const fileSizeInBytes = 2048;

  describe("default conversion", () => {
    it("should convert to KB", () => {
      const resultKB = convertBytes(fileSizeInBytes);
      expect(resultKB).toBe("2.05 KB");
    });

    it("should convert to MB", () => {
      const resultMB = convertBytes(fileSizeInBytes * 1000);
      expect(resultMB).toBe("2.05 MB");
    });

    it("should throw an error for invalid decimals", () => {
      expect(() => convertBytes(fileSizeInBytes, { decimals: -1 })).toThrowError("Invalid decimals -1");
    });
  });

  describe("conversion to binary units", () => {
    it("should convert to KiB", () => {
      const resultKiB = convertBytes(fileSizeInBytes, { useBinaryUnits: true });
      expect(resultKiB).toBe("2.00 KiB");
    });

    it("should convert to MiB", () => {
      const resultMiB = convertBytes(fileSizeInBytes * 1024, { useBinaryUnits: true });
      expect(resultMiB).toBe("2.00 MiB");
    });
  });

  it("should handle very large bytes (Number.MAX_SAFE_INTEGER)", () => {
    const result = convertBytes(Number.MAX_SAFE_INTEGER);
    expect(result).toBe("9.01 PB");
  });
});

@artembelik

Copy link
Copy Markdown
  const units = ["byte", "kilobyte", "megabyte", "terabyte", "petabyte"];

you lost "gigabyte"

@weroro-sk

Copy link
Copy Markdown

@gynekolog I implemented a simple word declension for the word "byte".

export const convertBytes = (bytes: number, options: { useBinaryUnits?: boolean; decimals?: number } = {}): string => {
    const {useBinaryUnits = false, decimals = 2} = options;

    if (decimals < 0)
        throw new Error(`Invalid decimals ${decimals}`);

    const declension = <T extends unknown>(num: number, dictionary: T[]): T =>
        (num = Math.abs(num)) === 1
            ? dictionary[1]
            : (num > 1 && num < 5)
                ? dictionary[2]
                : dictionary[0];

    const base = useBinaryUnits ? 1024 : 1000;
    const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(base));
    const value = bytes / Math.pow(base, i);
    const units = useBinaryUnits
        ? [["Bytes", "Byte", "Bytes"], "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]
        : [["Bytes", "Byte", "Bytes"], "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];

    let unit = units[i];

    return `${value.toFixed(decimals)} ${Array.isArray(unit) ? declension(value, unit) : unit}`;
}

Example:

convertBytes(0); // 0 Bytes
convertBytes(1); // 1 Byte
convertBytes(2); // 2 Bytes
convertBytes(3); // 3 Bytes
convertBytes(6); // 6 Bytes
convertBytes(987); // 987 Bytes
convertBytes(34523465); // 34.52 MB

I'm from Slovakia, so in my case it would be:

const units = useBinaryUnits
    ? [["Bajtov", "Bajt", "Bajty"], "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]
    : [["Bajtov", "Bajt", "Bajty"], "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
convertBytes(0); // 0 Bajtov
convertBytes(1); // 1 Bajt
convertBytes(2); // 2 Bajty
convertBytes(3); // 3 Bajty
convertBytes(4); // 4 Bajty
convertBytes(5); // 5 Bajtov
convertBytes(6); // 6 Bajtov
convertBytes(987); // 987 Bajtov
convertBytes(34523465); // 34.52 MB

@gynekolog

Copy link
Copy Markdown

@weroro-sk Good point, thanks for sharing! I gave it a try my way just for fun. The code uses Intl.PluralRules, but the whole function is more robust now. Feel free to check it out.

@brianmontanaocient

Copy link
Copy Markdown

Shouldn't 999999999 return 1 GB and not 1000 MB, since 1000000000 returns 1 GB.

@flycran

flycran commented Mar 15, 2026

Copy link
Copy Markdown

If you find yourself tweaking this snippet frequently, smart-unit might be worth a look — it handles this out of the box with configurable decimal places, TypeScript support, and bidirectional format/parse:

const size = new SmartUnit(['B', 'KB', 'MB', 'GB', 'TB'], { baseDigit: 1024 });
size.format(1234);    // "1.21KB"
size.parse('1.5GB'); // 1610612736

And bytes formatting is just one use case — the same API works for any unit system with variable ratios, like time, length, frequency, or anything custom:

const time = new SmartUnit(['ms', 1000, 's', 60, 'm', 60, 'h']);
time.format(5400000); // "1.5h"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment