Skip to content

Instantly share code, notes, and snippets.

@lanqy
Created March 19, 2013 03:05
  • Star 97 You must be signed in to star a gist
  • Fork 24 You must be signed in to fork a gist
Star You must be signed in to star a gist
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];
};
@williamoliveira
Copy link

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

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

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
Copy link

seahindeniz commented Dec 24, 2018

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
Copy link

jedfoster commented Jan 3, 2019

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
Copy link

jzombie commented Oct 17, 2019

@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
Copy link

StasAreshin commented Jan 13, 2020

  • 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
Copy link

Akifcan commented Feb 3, 2020

thank you

@ZachMoreno
Copy link

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
Copy link

zackster commented Apr 14, 2020

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

Thanks all of you

@ahmnouira
Copy link

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
Copy link

trankov commented Jul 14, 2021

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

@denik1981
Copy link

denik1981 commented Aug 27, 2021

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
Copy link

rmorlok commented Jul 8, 2022

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
Copy link

Dymerz commented Nov 23, 2022

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
Copy link

HaukeHa commented Sep 28, 2023

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
Copy link

gynekolog commented Nov 9, 2023

@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");
  });
});

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