10

Convert Bytes values into GB/MB/KB, i am using ByteCountFormatter. Example code below.

func converByteToGB(_ bytes:Int64) -> String {
        let formatter:ByteCountFormatter = ByteCountFormatter()
        formatter.countStyle = .binary

        return formatter.string(fromByteCount: Int64(bytes))
    }

Now, my requirement is it should show only one digit after decimal point. Example for 1.24 GB => 1.2 GB, not like 1.24 GB. force it for single digit after apply floor or ceil function.

Sheshnath
  • 3,293
  • 1
  • 32
  • 60

1 Answers1

15

ByteCountFormatter is not capable to show only one digit after decimal point. It shows by default 0 fraction digits for bytes and KB; 1 fraction digits for MB; 2 for GB and above. If isAdaptive is set to false it tries to show at least three significant digits, introducing fraction digits as necessary.

ByteCountFormatter also trims trailing zeros. To disable set zeroPadsFractionDigits to true.

I have adapted How to convert byte size into human readable format in java? to do what you want:

func humanReadableByteCount(bytes: Int) -> String {
    if (bytes < 1000) { return "\(bytes) B" }
    let exp = Int(log2(Double(bytes)) / log2(1000.0))
    let unit = ["KB", "MB", "GB", "TB", "PB", "EB"][exp - 1]
    let number = Double(bytes) / pow(1000, Double(exp))
    return String(format: "%.1f %@", number, unit)
}

Notice this will format KB and MB differently than ByteCountFormatter. Here is a modification that removes trailing zero and does not show fraction digits for KB and for numbers larger than 100.

func humanReadableByteCount(bytes: Int) -> String {
    if (bytes < 1000) { return "\(bytes) B" }
    let exp = Int(log2(Double(bytes)) / log2(1000.0))
    let unit = ["KB", "MB", "GB", "TB", "PB", "EB"][exp - 1]
    let number = Double(bytes) / pow(1000, Double(exp))
    if exp <= 1 || number >= 100 {
        return String(format: "%.0f %@", number, unit)
    } else {
        return String(format: "%.1f %@", number, unit)
            .replacingOccurrences(of: ".0", with: "")
    }
}

Be also aware that this implementation does not take Locale into account. For example some locales use comma (",") instead of dot (".") as decimal separator.

Marián Černý
  • 15,096
  • 4
  • 70
  • 83
  • great..did my job! Thanks – Hrishikesh Menon Jul 19 '19 at 06:52
  • thank you Marián, one hint: for binary you should replace all `1000` by `1024` ?? Since 1GB = 1024 * 1024 * 1024 bytes – iKK Oct 30 '20 at 15:05
  • Yes, for binary you would use `1024` instead of `1000`. The code however is for SI (International System of Units) which also Apple is using (in iOS, or in Finder on macOS). If you are using binary, you should probably use KiB (kibibyte), MiB, GiB, etc. instead of kB, MB, GB. Also note I am using KB instead of kB, because that's the way Apple uses it (uppercased). – Marián Černý Oct 31 '20 at 17:14