time.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package format
  2. import (
  3. "fmt"
  4. "math"
  5. "strings"
  6. "time"
  7. )
  8. // HumanDuration returns a human-readable approximation of a duration
  9. // (eg. "About a minute", "4 hours ago", etc.).
  10. // Modified version of github.com/docker/go-units.HumanDuration
  11. func HumanDuration(d time.Duration) string {
  12. return HumanDurationWithCase(d, true)
  13. }
  14. // HumanDurationWithCase returns a human-readable approximation of a
  15. // duration (eg. "About a minute", "4 hours ago", etc.). but allows
  16. // you to specify whether the first word should be capitalized
  17. // (eg. "About" vs. "about")
  18. func HumanDurationWithCase(d time.Duration, useCaps bool) string {
  19. seconds := int(d.Seconds())
  20. switch {
  21. case seconds < 1:
  22. if useCaps {
  23. return "Less than a second"
  24. }
  25. return "less than a second"
  26. case seconds == 1:
  27. return "1 second"
  28. case seconds < 60:
  29. return fmt.Sprintf("%d seconds", seconds)
  30. }
  31. minutes := int(d.Minutes())
  32. switch {
  33. case minutes == 1:
  34. if useCaps {
  35. return "About a minute"
  36. }
  37. return "about a minute"
  38. case minutes < 60:
  39. return fmt.Sprintf("%d minutes", minutes)
  40. }
  41. hours := int(math.Round(d.Hours()))
  42. switch {
  43. case hours == 1:
  44. if useCaps {
  45. return "About an hour"
  46. }
  47. return "about an hour"
  48. case hours < 48:
  49. return fmt.Sprintf("%d hours", hours)
  50. case hours < 24*7*2:
  51. return fmt.Sprintf("%d days", hours/24)
  52. case hours < 24*30*2:
  53. return fmt.Sprintf("%d weeks", hours/24/7)
  54. case hours < 24*365*2:
  55. return fmt.Sprintf("%d months", hours/24/30)
  56. }
  57. return fmt.Sprintf("%d years", int(d.Hours())/24/365)
  58. }
  59. func HumanTime(t time.Time, zeroValue string) string {
  60. return humanTimeWithCase(t, zeroValue, true)
  61. }
  62. func HumanTimeLower(t time.Time, zeroValue string) string {
  63. return humanTimeWithCase(t, zeroValue, false)
  64. }
  65. func humanTimeWithCase(t time.Time, zeroValue string, useCaps bool) string {
  66. if t.IsZero() {
  67. return zeroValue
  68. }
  69. delta := time.Since(t)
  70. if delta < 0 {
  71. return HumanDurationWithCase(-delta, useCaps) + " from now"
  72. }
  73. return HumanDurationWithCase(delta, useCaps) + " ago"
  74. }
  75. // ExcatDuration returns a human readable hours/minutes/seconds or milliseconds format of a duration
  76. // the most precise level of duration is milliseconds
  77. func ExactDuration(d time.Duration) string {
  78. if d.Seconds() < 1 {
  79. if d.Milliseconds() == 1 {
  80. return fmt.Sprintf("%d millisecond", d.Milliseconds())
  81. }
  82. return fmt.Sprintf("%d milliseconds", d.Milliseconds())
  83. }
  84. var readableDur strings.Builder
  85. dur := d.String()
  86. // split the default duration string format of 0h0m0s into something nicer to read
  87. h := strings.Split(dur, "h")
  88. if len(h) > 1 {
  89. hours := h[0]
  90. if hours == "1" {
  91. readableDur.WriteString(fmt.Sprintf("%s hour ", hours))
  92. } else {
  93. readableDur.WriteString(fmt.Sprintf("%s hours ", hours))
  94. }
  95. dur = h[1]
  96. }
  97. m := strings.Split(dur, "m")
  98. if len(m) > 1 {
  99. mins := m[0]
  100. switch mins {
  101. case "0":
  102. // skip
  103. case "1":
  104. readableDur.WriteString(fmt.Sprintf("%s minute ", mins))
  105. default:
  106. readableDur.WriteString(fmt.Sprintf("%s minutes ", mins))
  107. }
  108. dur = m[1]
  109. }
  110. s := strings.Split(dur, "s")
  111. if len(s) > 0 {
  112. sec := s[0]
  113. switch sec {
  114. case "0":
  115. // skip
  116. case "1":
  117. readableDur.WriteString(fmt.Sprintf("%s second ", sec))
  118. default:
  119. readableDur.WriteString(fmt.Sprintf("%s seconds ", sec))
  120. }
  121. }
  122. return strings.TrimSpace(readableDur.String())
  123. }