You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

341 lines
8.4 KiB

  1. // Copyright 2013 The Prometheus Authors
  2. // Licensed under the Apache License, Version 2.0 (the "License");
  3. // you may not use this file except in compliance with the License.
  4. // You may obtain a copy of the License at
  5. //
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. package model
  14. import (
  15. "encoding/json"
  16. "errors"
  17. "fmt"
  18. "math"
  19. "strconv"
  20. "strings"
  21. "time"
  22. )
  23. const (
  24. // MinimumTick is the minimum supported time resolution. This has to be
  25. // at least time.Second in order for the code below to work.
  26. minimumTick = time.Millisecond
  27. // second is the Time duration equivalent to one second.
  28. second = int64(time.Second / minimumTick)
  29. // The number of nanoseconds per minimum tick.
  30. nanosPerTick = int64(minimumTick / time.Nanosecond)
  31. // Earliest is the earliest Time representable. Handy for
  32. // initializing a high watermark.
  33. Earliest = Time(math.MinInt64)
  34. // Latest is the latest Time representable. Handy for initializing
  35. // a low watermark.
  36. Latest = Time(math.MaxInt64)
  37. )
  38. // Time is the number of milliseconds since the epoch
  39. // (1970-01-01 00:00 UTC) excluding leap seconds.
  40. type Time int64
  41. // Interval describes an interval between two timestamps.
  42. type Interval struct {
  43. Start, End Time
  44. }
  45. // Now returns the current time as a Time.
  46. func Now() Time {
  47. return TimeFromUnixNano(time.Now().UnixNano())
  48. }
  49. // TimeFromUnix returns the Time equivalent to the Unix Time t
  50. // provided in seconds.
  51. func TimeFromUnix(t int64) Time {
  52. return Time(t * second)
  53. }
  54. // TimeFromUnixNano returns the Time equivalent to the Unix Time
  55. // t provided in nanoseconds.
  56. func TimeFromUnixNano(t int64) Time {
  57. return Time(t / nanosPerTick)
  58. }
  59. // Equal reports whether two Times represent the same instant.
  60. func (t Time) Equal(o Time) bool {
  61. return t == o
  62. }
  63. // Before reports whether the Time t is before o.
  64. func (t Time) Before(o Time) bool {
  65. return t < o
  66. }
  67. // After reports whether the Time t is after o.
  68. func (t Time) After(o Time) bool {
  69. return t > o
  70. }
  71. // Add returns the Time t + d.
  72. func (t Time) Add(d time.Duration) Time {
  73. return t + Time(d/minimumTick)
  74. }
  75. // Sub returns the Duration t - o.
  76. func (t Time) Sub(o Time) time.Duration {
  77. return time.Duration(t-o) * minimumTick
  78. }
  79. // Time returns the time.Time representation of t.
  80. func (t Time) Time() time.Time {
  81. return time.Unix(int64(t)/second, (int64(t)%second)*nanosPerTick)
  82. }
  83. // Unix returns t as a Unix time, the number of seconds elapsed
  84. // since January 1, 1970 UTC.
  85. func (t Time) Unix() int64 {
  86. return int64(t) / second
  87. }
  88. // UnixNano returns t as a Unix time, the number of nanoseconds elapsed
  89. // since January 1, 1970 UTC.
  90. func (t Time) UnixNano() int64 {
  91. return int64(t) * nanosPerTick
  92. }
  93. // The number of digits after the dot.
  94. var dotPrecision = int(math.Log10(float64(second)))
  95. // String returns a string representation of the Time.
  96. func (t Time) String() string {
  97. return strconv.FormatFloat(float64(t)/float64(second), 'f', -1, 64)
  98. }
  99. // MarshalJSON implements the json.Marshaler interface.
  100. func (t Time) MarshalJSON() ([]byte, error) {
  101. return []byte(t.String()), nil
  102. }
  103. // UnmarshalJSON implements the json.Unmarshaler interface.
  104. func (t *Time) UnmarshalJSON(b []byte) error {
  105. p := strings.Split(string(b), ".")
  106. switch len(p) {
  107. case 1:
  108. v, err := strconv.ParseInt(string(p[0]), 10, 64)
  109. if err != nil {
  110. return err
  111. }
  112. *t = Time(v * second)
  113. case 2:
  114. v, err := strconv.ParseInt(string(p[0]), 10, 64)
  115. if err != nil {
  116. return err
  117. }
  118. v *= second
  119. prec := dotPrecision - len(p[1])
  120. if prec < 0 {
  121. p[1] = p[1][:dotPrecision]
  122. } else if prec > 0 {
  123. p[1] = p[1] + strings.Repeat("0", prec)
  124. }
  125. va, err := strconv.ParseInt(p[1], 10, 32)
  126. if err != nil {
  127. return err
  128. }
  129. // If the value was something like -0.1 the negative is lost in the
  130. // parsing because of the leading zero, this ensures that we capture it.
  131. if len(p[0]) > 0 && p[0][0] == '-' && v+va > 0 {
  132. *t = Time(v+va) * -1
  133. } else {
  134. *t = Time(v + va)
  135. }
  136. default:
  137. return fmt.Errorf("invalid time %q", string(b))
  138. }
  139. return nil
  140. }
  141. // Duration wraps time.Duration. It is used to parse the custom duration format
  142. // from YAML.
  143. // This type should not propagate beyond the scope of input/output processing.
  144. type Duration time.Duration
  145. // Set implements pflag/flag.Value
  146. func (d *Duration) Set(s string) error {
  147. var err error
  148. *d, err = ParseDuration(s)
  149. return err
  150. }
  151. // Type implements pflag.Value
  152. func (d *Duration) Type() string {
  153. return "duration"
  154. }
  155. func isdigit(c byte) bool { return c >= '0' && c <= '9' }
  156. // Units are required to go in order from biggest to smallest.
  157. // This guards against confusion from "1m1d" being 1 minute + 1 day, not 1 month + 1 day.
  158. var unitMap = map[string]struct {
  159. pos int
  160. mult uint64
  161. }{
  162. "ms": {7, uint64(time.Millisecond)},
  163. "s": {6, uint64(time.Second)},
  164. "m": {5, uint64(time.Minute)},
  165. "h": {4, uint64(time.Hour)},
  166. "d": {3, uint64(24 * time.Hour)},
  167. "w": {2, uint64(7 * 24 * time.Hour)},
  168. "y": {1, uint64(365 * 24 * time.Hour)},
  169. }
  170. // ParseDuration parses a string into a time.Duration, assuming that a year
  171. // always has 365d, a week always has 7d, and a day always has 24h.
  172. func ParseDuration(s string) (Duration, error) {
  173. switch s {
  174. case "0":
  175. // Allow 0 without a unit.
  176. return 0, nil
  177. case "":
  178. return 0, errors.New("empty duration string")
  179. }
  180. orig := s
  181. var dur uint64
  182. lastUnitPos := 0
  183. for s != "" {
  184. if !isdigit(s[0]) {
  185. return 0, fmt.Errorf("not a valid duration string: %q", orig)
  186. }
  187. // Consume [0-9]*
  188. i := 0
  189. for ; i < len(s) && isdigit(s[i]); i++ {
  190. }
  191. v, err := strconv.ParseUint(s[:i], 10, 0)
  192. if err != nil {
  193. return 0, fmt.Errorf("not a valid duration string: %q", orig)
  194. }
  195. s = s[i:]
  196. // Consume unit.
  197. for i = 0; i < len(s) && !isdigit(s[i]); i++ {
  198. }
  199. if i == 0 {
  200. return 0, fmt.Errorf("not a valid duration string: %q", orig)
  201. }
  202. u := s[:i]
  203. s = s[i:]
  204. unit, ok := unitMap[u]
  205. if !ok {
  206. return 0, fmt.Errorf("unknown unit %q in duration %q", u, orig)
  207. }
  208. if unit.pos <= lastUnitPos { // Units must go in order from biggest to smallest.
  209. return 0, fmt.Errorf("not a valid duration string: %q", orig)
  210. }
  211. lastUnitPos = unit.pos
  212. // Check if the provided duration overflows time.Duration (> ~ 290years).
  213. if v > 1<<63/unit.mult {
  214. return 0, errors.New("duration out of range")
  215. }
  216. dur += v * unit.mult
  217. if dur > 1<<63-1 {
  218. return 0, errors.New("duration out of range")
  219. }
  220. }
  221. return Duration(dur), nil
  222. }
  223. func (d Duration) String() string {
  224. var (
  225. ms = int64(time.Duration(d) / time.Millisecond)
  226. r = ""
  227. )
  228. if ms == 0 {
  229. return "0s"
  230. }
  231. f := func(unit string, mult int64, exact bool) {
  232. if exact && ms%mult != 0 {
  233. return
  234. }
  235. if v := ms / mult; v > 0 {
  236. r += fmt.Sprintf("%d%s", v, unit)
  237. ms -= v * mult
  238. }
  239. }
  240. // Only format years and weeks if the remainder is zero, as it is often
  241. // easier to read 90d than 12w6d.
  242. f("y", 1000*60*60*24*365, true)
  243. f("w", 1000*60*60*24*7, true)
  244. f("d", 1000*60*60*24, false)
  245. f("h", 1000*60*60, false)
  246. f("m", 1000*60, false)
  247. f("s", 1000, false)
  248. f("ms", 1, false)
  249. return r
  250. }
  251. // MarshalJSON implements the json.Marshaler interface.
  252. func (d Duration) MarshalJSON() ([]byte, error) {
  253. return json.Marshal(d.String())
  254. }
  255. // UnmarshalJSON implements the json.Unmarshaler interface.
  256. func (d *Duration) UnmarshalJSON(bytes []byte) error {
  257. var s string
  258. if err := json.Unmarshal(bytes, &s); err != nil {
  259. return err
  260. }
  261. dur, err := ParseDuration(s)
  262. if err != nil {
  263. return err
  264. }
  265. *d = dur
  266. return nil
  267. }
  268. // MarshalText implements the encoding.TextMarshaler interface.
  269. func (d *Duration) MarshalText() ([]byte, error) {
  270. return []byte(d.String()), nil
  271. }
  272. // UnmarshalText implements the encoding.TextUnmarshaler interface.
  273. func (d *Duration) UnmarshalText(text []byte) error {
  274. var err error
  275. *d, err = ParseDuration(string(text))
  276. return err
  277. }
  278. // MarshalYAML implements the yaml.Marshaler interface.
  279. func (d Duration) MarshalYAML() (interface{}, error) {
  280. return d.String(), nil
  281. }
  282. // UnmarshalYAML implements the yaml.Unmarshaler interface.
  283. func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error {
  284. var s string
  285. if err := unmarshal(&s); err != nil {
  286. return err
  287. }
  288. dur, err := ParseDuration(s)
  289. if err != nil {
  290. return err
  291. }
  292. *d = dur
  293. return nil
  294. }