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];
};
@pe77

pe77 commented Nov 24, 2015

Copy link
Copy Markdown

Nice

@williamoliveira

Copy link
Copy Markdown

ES6 and airbnb's eslint compliant version:

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

@Oluwasetemi

Copy link
Copy Markdown

function bytesToSize(bytes) {
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
if (bytes === 0) return 'n/a'
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10)
if (i === 0) return ${bytes} ${sizes[i]})
return ${(bytes / (1024 ** i)).toFixed(1)} ${sizes[i]}
}

@deathwebo

Copy link
Copy Markdown

With little typo fixed on line 5:

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

@seahindeniz

seahindeniz commented Dec 24, 2018

Copy link
Copy Markdown

Some may doesn't like having a seperator so:

function bytesToSize(bytes, seperator = "") {
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
  if (bytes == 0) return 'n/a'
  const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10)
  if (i === 0) return `${bytes}${seperator}${sizes[i]}`
  return `${(bytes / (1024 ** i)).toFixed(1)}${seperator}${sizes[i]}`
}

console.log( bytesToSize(2659633) ); // 2.5MB
console.log( bytesToSize(2659633, " ") ); // 2.5 MB
console.log( bytesToSize(2659633, "-") ); // 2.5-MB

@jedfoster

jedfoster commented Jan 3, 2019

Copy link
Copy Markdown

I had a need to format negative values, but Math.log(x) returns NaN if x is negative, so I pass bytes through Math.abs() first.

function bytesToSize(bytes) {
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
  if (bytes === 0) return 'n/a';
  const i = parseInt(Math.floor(Math.log(Math.abs(bytes)) / Math.log(1024)), 10);
  if (i === 0) return `${bytes} ${sizes[i]}`;
  return `${(bytes / (1024 ** i)).toFixed(1)} ${sizes[i]}`;
}

console.log(bytesToSize(1234567)); // 1.2 MB
console.log(bytesToSize(-1234567)); // -1.2 MB

@jzombie

jzombie commented Oct 17, 2019

Copy link
Copy Markdown

@jedfoster I used your code, but just pointing out something... If you're only rendering "Bytes", there's a dangling closing parenthesis.

e.g. "Bytes)"

@StasAreshin

StasAreshin commented Jan 13, 2020

Copy link
Copy Markdown
  • 1 redundant line removed
  • added suffix param
  • fixed error if size more then 1023 TB
function prettySize(bytes, separator = '', postFix = '') {
    if (bytes) {
        const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        const i = Math.min(parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10), sizes.length - 1);
        return `${(bytes / (1024 ** i)).toFixed(i ? 1 : 0)}${separator}${sizes[i]}${postFix}`;
    }
    return 'n/a';
}

@Akifcan

Akifcan commented Feb 3, 2020

Copy link
Copy Markdown

thank you

@ZachMoreno

Copy link
Copy Markdown

fixed a type error on line 4, Argument of type 'number' is not assignable to parameter of type 'string'

prettySize(bytes, separator = '', postFix = '') {
    if (bytes) {
        const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        const i = Math.min(parseInt(Math.floor(Math.log(bytes) / Math.log(1024)).toString(), 10), sizes.length - 1);
        return `${(bytes / (1024 ** i)).toFixed(i ? 1 : 0)}${separator}${sizes[i]}${postFix}`;
    }
    return 'n/a';
}

@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