From 524486b412a21f620d0fd7b9a6f62194f525c2fc Mon Sep 17 00:00:00 2001 From: Nathan Nguyen Date: Mon, 29 Dec 2025 22:05:26 -0500 Subject: [PATCH] format: use binary prefixes for HumanBytes file size formatting Change HumanBytes to use binary prefixes (1024-based) instead of decimal (1000-based) for file size formatting. This fixes the rounding error where 3072 bytes was displayed as '3.1 KB' instead of '3 KB'. The decimal constants (KiloByte, MegaByte, etc.) are preserved for other uses like buffer sizes and memory capacity. Fixes #13405 --- format/bytes.go | 21 +++++++++++++-------- format/bytes_test.go | 42 ++++++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/format/bytes.go b/format/bytes.go index a24231df2..c97f72381 100644 --- a/format/bytes.go +++ b/format/bytes.go @@ -8,32 +8,37 @@ import ( const ( Byte = 1 + // Decimal prefixes (1000-based) - used for buffer sizes, memory capacity KiloByte = Byte * 1000 MegaByte = KiloByte * 1000 GigaByte = MegaByte * 1000 TeraByte = GigaByte * 1000 + // Binary prefixes (1024-based) - used for file sizes KibiByte = Byte * 1024 MebiByte = KibiByte * 1024 GibiByte = MebiByte * 1024 + TebiByte = GibiByte * 1024 ) +// HumanBytes formats bytes using binary prefixes (1024-based) with short unit names. +// This follows the convention used by most file systems and tools for file sizes. func HumanBytes(b int64) string { var value float64 var unit string switch { - case b >= TeraByte: - value = float64(b) / TeraByte + case b >= TebiByte: + value = float64(b) / TebiByte unit = "TB" - case b >= GigaByte: - value = float64(b) / GigaByte + case b >= GibiByte: + value = float64(b) / GibiByte unit = "GB" - case b >= MegaByte: - value = float64(b) / MegaByte + case b >= MebiByte: + value = float64(b) / MebiByte unit = "MB" - case b >= KiloByte: - value = float64(b) / KiloByte + case b >= KibiByte: + value = float64(b) / KibiByte unit = "KB" default: return fmt.Sprintf("%d B", b) diff --git a/format/bytes_test.go b/format/bytes_test.go index 5881af45c..45cb7a9aa 100644 --- a/format/bytes_test.go +++ b/format/bytes_test.go @@ -14,32 +14,34 @@ func TestHumanBytes(t *testing.T) { // Test bytes (B) {0, "0 B"}, {1, "1 B"}, - {999, "999 B"}, + {1023, "1023 B"}, - // Test kilobytes (KB) - {1000, "1 KB"}, - {1500, "1.5 KB"}, - {999999, "999 KB"}, + // Test kilobytes (KB) - binary prefix (1024-based) + {1024, "1 KB"}, + {1536, "1.5 KB"}, + {3072, "3 KB"}, + {4096, "4 KB"}, + {10240, "10 KB"}, - // Test megabytes (MB) - {1000000, "1 MB"}, - {1500000, "1.5 MB"}, - {999999999, "999 MB"}, + // Test megabytes (MB) - binary prefix (1024-based) + {1048576, "1 MB"}, + {1572864, "1.5 MB"}, + {10485760, "10 MB"}, - // Test gigabytes (GB) - {1000000000, "1 GB"}, - {1500000000, "1.5 GB"}, - {999999999999, "999 GB"}, + // Test gigabytes (GB) - binary prefix (1024-based) + {1073741824, "1 GB"}, + {1610612736, "1.5 GB"}, + {10737418240, "10 GB"}, - // Test terabytes (TB) - {1000000000000, "1 TB"}, - {1500000000000, "1.5 TB"}, - {1999999999999, "2.0 TB"}, + // Test terabytes (TB) - binary prefix (1024-based) + {1099511627776, "1 TB"}, + {1649267441664, "1.5 TB"}, + {2199023255552, "2 TB"}, // Test fractional values - {1234, "1.2 KB"}, - {1234567, "1.2 MB"}, - {1234567890, "1.2 GB"}, + {1280, "1.2 KB"}, + {1310720, "1.2 MB"}, + {1342177280, "1.2 GB"}, } for _, tc := range tests {