package pb import ( "fmt" "time" ) type Units int const ( // U_NO are default units, they represent a simple value and are not formatted at all. U_NO Units = iota // U_BYTES units are formatted in a human readable way (B, KiB, MiB, ...) U_BYTES // U_BYTES_DEC units are like U_BYTES, but base 10 (B, KB, MB, ...) U_BYTES_DEC // U_DURATION units are formatted in a human readable way (3h14m15s) U_DURATION ) const ( KiB = 1024 MiB = 1048576 GiB = 1073741824 TiB = 1099511627776 KB = 1e3 MB = 1e6 GB = 1e9 TB = 1e12 ) func Format(i int64) *formatter { return &formatter{n: i} } type formatter struct { n int64 unit Units width int perSec bool } func (f *formatter) To(unit Units) *formatter { f.unit = unit return f } func (f *formatter) Width(width int) *formatter { f.width = width return f } func (f *formatter) PerSec() *formatter { f.perSec = true return f } func (f *formatter) String() (out string) { switch f.unit { case U_BYTES: out = formatBytes(f.n) case U_BYTES_DEC: out = formatBytesDec(f.n) case U_DURATION: out = formatDuration(f.n) default: out = fmt.Sprintf(fmt.Sprintf("%%%dd", f.width), f.n) } if f.perSec { out += "/s" } return } // Convert bytes to human readable string. Like 2 MiB, 64.2 KiB, 52 B func formatBytes(i int64) (result string) { switch { case i >= TiB: result = fmt.Sprintf("%.02f TiB", float64(i)/TiB) case i >= GiB: result = fmt.Sprintf("%.02f GiB", float64(i)/GiB) case i >= MiB: result = fmt.Sprintf("%.02f MiB", float64(i)/MiB) case i >= KiB: result = fmt.Sprintf("%.02f KiB", float64(i)/KiB) default: result = fmt.Sprintf("%d B", i) } return } // Convert bytes to base-10 human readable string. Like 2 MB, 64.2 KB, 52 B func formatBytesDec(i int64) (result string) { switch { case i >= TB: result = fmt.Sprintf("%.02f TB", float64(i)/TB) case i >= GB: result = fmt.Sprintf("%.02f GB", float64(i)/GB) case i >= MB: result = fmt.Sprintf("%.02f MB", float64(i)/MB) case i >= KB: result = fmt.Sprintf("%.02f KB", float64(i)/KB) default: result = fmt.Sprintf("%d B", i) } return } func formatDuration(n int64) (result string) { d := time.Duration(n) if d > time.Hour*24 { result = fmt.Sprintf("%dd", d/24/time.Hour) d -= (d / time.Hour / 24) * (time.Hour * 24) } result = fmt.Sprintf("%s%v", result, d) return }