-
Star
(103)
You must be signed in to star a gist -
Fork
(26)
You must be signed in to fork a gist
-
-
Save lanqy/5193417 to your computer and use it in GitHub Desktop.
// 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]; | |
}; |
Strength and power of open source community. I'm shocked and impressed. Thanks to all, guys.
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);
}
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);
});
});
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))
}
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'.
@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");
});
});
const units = ["byte", "kilobyte", "megabyte", "terabyte", "petabyte"];
you lost "gigabyte"
@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
@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.
TypeScript version: