time.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package util
  2. import (
  3. "fmt"
  4. "strconv"
  5. "time"
  6. )
  7. const (
  8. // SecsPerMin expresses the amount of seconds in a minute
  9. SecsPerMin = 60.0
  10. // SecsPerHour expresses the amount of seconds in a minute
  11. SecsPerHour = 3600.0
  12. // SecsPerDay expressed the amount of seconds in a day
  13. SecsPerDay = 86400.0
  14. // MinsPerHour expresses the amount of minutes in an hour
  15. MinsPerHour = 60.0
  16. // MinsPerDay expresses the amount of minutes in a day
  17. MinsPerDay = 1440.0
  18. // HoursPerDay expresses the amount of hours in a day
  19. HoursPerDay = 24.0
  20. // HoursPerMonth expresses the amount of hours in a month
  21. HoursPerMonth = 730.0
  22. // DaysPerMonth expresses the amount of days in a month
  23. DaysPerMonth = 30.42
  24. )
  25. // DurationOffsetStrings converts a (duration, offset) pair to Prometheus-
  26. // compatible strings in terms of days, hours, minutes, or seconds.
  27. func DurationOffsetStrings(duration, offset time.Duration) (string, string) {
  28. durSecs := int64(duration.Seconds())
  29. offSecs := int64(offset.Seconds())
  30. durStr := ""
  31. if durSecs > 0 {
  32. if durSecs%SecsPerDay == 0 {
  33. // convert to days
  34. durStr = fmt.Sprintf("%dd", durSecs/SecsPerDay)
  35. } else if durSecs%SecsPerHour == 0 {
  36. // convert to hours
  37. durStr = fmt.Sprintf("%dh", durSecs/SecsPerHour)
  38. } else if durSecs%SecsPerMin == 0 {
  39. // convert to mins
  40. durStr = fmt.Sprintf("%dm", durSecs/SecsPerMin)
  41. } else if durSecs > 0 {
  42. // default to mins, as long as duration is positive
  43. durStr = fmt.Sprintf("%ds", durSecs)
  44. }
  45. }
  46. offStr := ""
  47. if offSecs > 0 {
  48. if offSecs%SecsPerDay == 0 {
  49. // convert to days
  50. offStr = fmt.Sprintf("%dd", offSecs/SecsPerDay)
  51. } else if offSecs%SecsPerHour == 0 {
  52. // convert to hours
  53. offStr = fmt.Sprintf("%dh", offSecs/SecsPerHour)
  54. } else if offSecs%SecsPerMin == 0 {
  55. // convert to mins
  56. offStr = fmt.Sprintf("%dm", offSecs/SecsPerMin)
  57. } else if offSecs > 0 {
  58. // default to mins, as long as offation is positive
  59. offStr = fmt.Sprintf("%ds", offSecs)
  60. }
  61. }
  62. return durStr, offStr
  63. }
  64. // ParseDuration converts a Prometheus-style duration string into a Duration
  65. func ParseDuration(duration string) (*time.Duration, error) {
  66. unitStr := duration[len(duration)-1:]
  67. var unit time.Duration
  68. switch unitStr {
  69. case "s":
  70. unit = time.Second
  71. case "m":
  72. unit = time.Minute
  73. case "h":
  74. unit = time.Hour
  75. case "d":
  76. unit = 24.0 * time.Hour
  77. default:
  78. return nil, fmt.Errorf("error parsing duration: %s did not match expected format [0-9+](s|m|d|h)", duration)
  79. }
  80. amountStr := duration[:len(duration)-1]
  81. amount, err := strconv.ParseInt(amountStr, 10, 64)
  82. if err != nil {
  83. return nil, fmt.Errorf("error parsing duration: %s did not match expected format [0-9+](s|m|d|h)", duration)
  84. }
  85. dur := time.Duration(amount) * unit
  86. return &dur, nil
  87. }
  88. // ParseTimeRange returns a start and end time, respectively, which are converted from
  89. // a duration and offset, defined as strings with Prometheus-style syntax.
  90. func ParseTimeRange(duration, offset string) (*time.Time, *time.Time, error) {
  91. // endTime defaults to the current time, unless an offset is explicity declared,
  92. // in which case it shifts endTime back by given duration
  93. endTime := time.Now()
  94. if offset != "" {
  95. o, err := ParseDuration(offset)
  96. if err != nil {
  97. return nil, nil, fmt.Errorf("error parsing offset (%s): %s", offset, err)
  98. }
  99. endTime = endTime.Add(-1 * *o)
  100. }
  101. // if duration is defined in terms of days, convert to hours
  102. // e.g. convert "2d" to "48h"
  103. durationNorm, err := normalizeTimeParam(duration)
  104. if err != nil {
  105. return nil, nil, fmt.Errorf("error parsing duration (%s): %s", duration, err)
  106. }
  107. // convert time duration into start and end times, formatted
  108. // as ISO datetime strings
  109. dur, err := time.ParseDuration(durationNorm)
  110. if err != nil {
  111. return nil, nil, fmt.Errorf("errorf parsing duration (%s): %s", durationNorm, err)
  112. }
  113. startTime := endTime.Add(-1 * dur)
  114. return &startTime, &endTime, nil
  115. }
  116. func normalizeTimeParam(param string) (string, error) {
  117. // convert days to hours
  118. if param[len(param)-1:] == "d" {
  119. count := param[:len(param)-1]
  120. val, err := strconv.ParseInt(count, 10, 64)
  121. if err != nil {
  122. return "", err
  123. }
  124. val = val * 24
  125. param = fmt.Sprintf("%dh", val)
  126. }
  127. return param, nil
  128. }