times.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package humanize
  2. import (
  3. "fmt"
  4. "math"
  5. "sort"
  6. "time"
  7. )
  8. // Seconds-based time units
  9. const (
  10. Minute = 60
  11. Hour = 60 * Minute
  12. Day = 24 * Hour
  13. Week = 7 * Day
  14. Month = 30 * Day
  15. Year = 12 * Month
  16. LongTime = 37 * Year
  17. )
  18. // Time formats a time into a relative string.
  19. //
  20. // Time(someT) -> "3 weeks ago"
  21. func Time(then time.Time) string {
  22. return RelTime(then, time.Now(), "ago", "from now")
  23. }
  24. var magnitudes = []struct {
  25. d int64
  26. format string
  27. divby int64
  28. }{
  29. {1, "now", 1},
  30. {2, "1 second %s", 1},
  31. {Minute, "%d seconds %s", 1},
  32. {2 * Minute, "1 minute %s", 1},
  33. {Hour, "%d minutes %s", Minute},
  34. {2 * Hour, "1 hour %s", 1},
  35. {Day, "%d hours %s", Hour},
  36. {2 * Day, "1 day %s", 1},
  37. {Week, "%d days %s", Day},
  38. {2 * Week, "1 week %s", 1},
  39. {Month, "%d weeks %s", Week},
  40. {2 * Month, "1 month %s", 1},
  41. {Year, "%d months %s", Month},
  42. {18 * Month, "1 year %s", 1},
  43. {2 * Year, "2 years %s", 1},
  44. {LongTime, "%d years %s", Year},
  45. {math.MaxInt64, "a long while %s", 1},
  46. }
  47. // RelTime formats a time into a relative string.
  48. //
  49. // It takes two times and two labels. In addition to the generic time
  50. // delta string (e.g. 5 minutes), the labels are used applied so that
  51. // the label corresponding to the smaller time is applied.
  52. //
  53. // RelTime(timeInPast, timeInFuture, "earlier", "later") -> "3 weeks earlier"
  54. func RelTime(a, b time.Time, albl, blbl string) string {
  55. lbl := albl
  56. diff := b.Unix() - a.Unix()
  57. after := a.After(b)
  58. if after {
  59. lbl = blbl
  60. diff = a.Unix() - b.Unix()
  61. }
  62. n := sort.Search(len(magnitudes), func(i int) bool {
  63. return magnitudes[i].d > diff
  64. })
  65. mag := magnitudes[n]
  66. args := []interface{}{}
  67. escaped := false
  68. for _, ch := range mag.format {
  69. if escaped {
  70. switch ch {
  71. case '%':
  72. case 's':
  73. args = append(args, lbl)
  74. case 'd':
  75. args = append(args, diff/mag.divby)
  76. }
  77. escaped = false
  78. } else {
  79. escaped = ch == '%'
  80. }
  81. }
  82. return fmt.Sprintf(mag.format, args...)
  83. }