format.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package pb
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. type Units int
  7. const (
  8. // U_NO are default units, they represent a simple value and are not formatted at all.
  9. U_NO Units = iota
  10. // U_BYTES units are formatted in a human readable way (B, KiB, MiB, ...)
  11. U_BYTES
  12. // U_BYTES_DEC units are like U_BYTES, but base 10 (B, KB, MB, ...)
  13. U_BYTES_DEC
  14. // U_DURATION units are formatted in a human readable way (3h14m15s)
  15. U_DURATION
  16. )
  17. const (
  18. KiB = 1024
  19. MiB = 1048576
  20. GiB = 1073741824
  21. TiB = 1099511627776
  22. KB = 1e3
  23. MB = 1e6
  24. GB = 1e9
  25. TB = 1e12
  26. )
  27. func Format(i int64) *formatter {
  28. return &formatter{n: i}
  29. }
  30. type formatter struct {
  31. n int64
  32. unit Units
  33. width int
  34. perSec bool
  35. }
  36. func (f *formatter) To(unit Units) *formatter {
  37. f.unit = unit
  38. return f
  39. }
  40. func (f *formatter) Width(width int) *formatter {
  41. f.width = width
  42. return f
  43. }
  44. func (f *formatter) PerSec() *formatter {
  45. f.perSec = true
  46. return f
  47. }
  48. func (f *formatter) String() (out string) {
  49. switch f.unit {
  50. case U_BYTES:
  51. out = formatBytes(f.n)
  52. case U_BYTES_DEC:
  53. out = formatBytesDec(f.n)
  54. case U_DURATION:
  55. out = formatDuration(f.n)
  56. default:
  57. out = fmt.Sprintf(fmt.Sprintf("%%%dd", f.width), f.n)
  58. }
  59. if f.perSec {
  60. out += "/s"
  61. }
  62. return
  63. }
  64. // Convert bytes to human readable string. Like 2 MiB, 64.2 KiB, 52 B
  65. func formatBytes(i int64) (result string) {
  66. switch {
  67. case i >= TiB:
  68. result = fmt.Sprintf("%.02f TiB", float64(i)/TiB)
  69. case i >= GiB:
  70. result = fmt.Sprintf("%.02f GiB", float64(i)/GiB)
  71. case i >= MiB:
  72. result = fmt.Sprintf("%.02f MiB", float64(i)/MiB)
  73. case i >= KiB:
  74. result = fmt.Sprintf("%.02f KiB", float64(i)/KiB)
  75. default:
  76. result = fmt.Sprintf("%d B", i)
  77. }
  78. return
  79. }
  80. // Convert bytes to base-10 human readable string. Like 2 MB, 64.2 KB, 52 B
  81. func formatBytesDec(i int64) (result string) {
  82. switch {
  83. case i >= TB:
  84. result = fmt.Sprintf("%.02f TB", float64(i)/TB)
  85. case i >= GB:
  86. result = fmt.Sprintf("%.02f GB", float64(i)/GB)
  87. case i >= MB:
  88. result = fmt.Sprintf("%.02f MB", float64(i)/MB)
  89. case i >= KB:
  90. result = fmt.Sprintf("%.02f KB", float64(i)/KB)
  91. default:
  92. result = fmt.Sprintf("%d B", i)
  93. }
  94. return
  95. }
  96. func formatDuration(n int64) (result string) {
  97. d := time.Duration(n)
  98. if d > time.Hour*24 {
  99. result = fmt.Sprintf("%dd", d/24/time.Hour)
  100. d -= (d / time.Hour / 24) * (time.Hour * 24)
  101. }
  102. if d > time.Hour {
  103. result = fmt.Sprintf("%s%dh", result, d/time.Hour)
  104. d -= d / time.Hour * time.Hour
  105. }
  106. m := d / time.Minute
  107. d -= m * time.Minute
  108. s := d / time.Second
  109. result = fmt.Sprintf("%s%02dm%02ds", result, m, s)
  110. return
  111. }