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 14package model 15 16import ( 17 "fmt" 18 "math" 19 "regexp" 20 "strconv" 21 "strings" 22 "time" 23) 24 25const ( 26 // MinimumTick is the minimum supported time resolution. This has to be 27 // at least time.Second in order for the code below to work. 28 minimumTick = time.Millisecond 29 // second is the Time duration equivalent to one second. 30 second = int64(time.Second / minimumTick) 31 // The number of nanoseconds per minimum tick. 32 nanosPerTick = int64(minimumTick / time.Nanosecond) 33 34 // Earliest is the earliest Time representable. Handy for 35 // initializing a high watermark. 36 Earliest = Time(math.MinInt64) 37 // Latest is the latest Time representable. Handy for initializing 38 // a low watermark. 39 Latest = Time(math.MaxInt64) 40) 41 42// Time is the number of milliseconds since the epoch 43// (1970-01-01 00:00 UTC) excluding leap seconds. 44type Time int64 45 46// Interval describes and interval between two timestamps. 47type Interval struct { 48 Start, End Time 49} 50 51// Now returns the current time as a Time. 52func Now() Time { 53 return TimeFromUnixNano(time.Now().UnixNano()) 54} 55 56// TimeFromUnix returns the Time equivalent to the Unix Time t 57// provided in seconds. 58func TimeFromUnix(t int64) Time { 59 return Time(t * second) 60} 61 62// TimeFromUnixNano returns the Time equivalent to the Unix Time 63// t provided in nanoseconds. 64func TimeFromUnixNano(t int64) Time { 65 return Time(t / nanosPerTick) 66} 67 68// Equal reports whether two Times represent the same instant. 69func (t Time) Equal(o Time) bool { 70 return t == o 71} 72 73// Before reports whether the Time t is before o. 74func (t Time) Before(o Time) bool { 75 return t < o 76} 77 78// After reports whether the Time t is after o. 79func (t Time) After(o Time) bool { 80 return t > o 81} 82 83// Add returns the Time t + d. 84func (t Time) Add(d time.Duration) Time { 85 return t + Time(d/minimumTick) 86} 87 88// Sub returns the Duration t - o. 89func (t Time) Sub(o Time) time.Duration { 90 return time.Duration(t-o) * minimumTick 91} 92 93// Time returns the time.Time representation of t. 94func (t Time) Time() time.Time { 95 return time.Unix(int64(t)/second, (int64(t)%second)*nanosPerTick) 96} 97 98// Unix returns t as a Unix time, the number of seconds elapsed 99// since January 1, 1970 UTC. 100func (t Time) Unix() int64 { 101 return int64(t) / second 102} 103 104// UnixNano returns t as a Unix time, the number of nanoseconds elapsed 105// since January 1, 1970 UTC. 106func (t Time) UnixNano() int64 { 107 return int64(t) * nanosPerTick 108} 109 110// The number of digits after the dot. 111var dotPrecision = int(math.Log10(float64(second))) 112 113// String returns a string representation of the Time. 114func (t Time) String() string { 115 return strconv.FormatFloat(float64(t)/float64(second), 'f', -1, 64) 116} 117 118// MarshalJSON implements the json.Marshaler interface. 119func (t Time) MarshalJSON() ([]byte, error) { 120 return []byte(t.String()), nil 121} 122 123// UnmarshalJSON implements the json.Unmarshaler interface. 124func (t *Time) UnmarshalJSON(b []byte) error { 125 p := strings.Split(string(b), ".") 126 switch len(p) { 127 case 1: 128 v, err := strconv.ParseInt(string(p[0]), 10, 64) 129 if err != nil { 130 return err 131 } 132 *t = Time(v * second) 133 134 case 2: 135 v, err := strconv.ParseInt(string(p[0]), 10, 64) 136 if err != nil { 137 return err 138 } 139 v *= second 140 141 prec := dotPrecision - len(p[1]) 142 if prec < 0 { 143 p[1] = p[1][:dotPrecision] 144 } else if prec > 0 { 145 p[1] = p[1] + strings.Repeat("0", prec) 146 } 147 148 va, err := strconv.ParseInt(p[1], 10, 32) 149 if err != nil { 150 return err 151 } 152 153 *t = Time(v + va) 154 155 default: 156 return fmt.Errorf("invalid time %q", string(b)) 157 } 158 return nil 159} 160 161// Duration wraps time.Duration. It is used to parse the custom duration format 162// from YAML. 163// This type should not propagate beyond the scope of input/output processing. 164type Duration time.Duration 165 166var durationRE = regexp.MustCompile("^([0-9]+)(y|w|d|h|m|s|ms)$") 167 168// StringToDuration parses a string into a time.Duration, assuming that a year 169// always has 365d, a week always has 7d, and a day always has 24h. 170func ParseDuration(durationStr string) (Duration, error) { 171 matches := durationRE.FindStringSubmatch(durationStr) 172 if len(matches) != 3 { 173 return 0, fmt.Errorf("not a valid duration string: %q", durationStr) 174 } 175 var ( 176 n, _ = strconv.Atoi(matches[1]) 177 dur = time.Duration(n) * time.Millisecond 178 ) 179 switch unit := matches[2]; unit { 180 case "y": 181 dur *= 1000 * 60 * 60 * 24 * 365 182 case "w": 183 dur *= 1000 * 60 * 60 * 24 * 7 184 case "d": 185 dur *= 1000 * 60 * 60 * 24 186 case "h": 187 dur *= 1000 * 60 * 60 188 case "m": 189 dur *= 1000 * 60 190 case "s": 191 dur *= 1000 192 case "ms": 193 // Value already correct 194 default: 195 return 0, fmt.Errorf("invalid time unit in duration string: %q", unit) 196 } 197 return Duration(dur), nil 198} 199 200func (d Duration) String() string { 201 var ( 202 ms = int64(time.Duration(d) / time.Millisecond) 203 unit = "ms" 204 ) 205 factors := map[string]int64{ 206 "y": 1000 * 60 * 60 * 24 * 365, 207 "w": 1000 * 60 * 60 * 24 * 7, 208 "d": 1000 * 60 * 60 * 24, 209 "h": 1000 * 60 * 60, 210 "m": 1000 * 60, 211 "s": 1000, 212 "ms": 1, 213 } 214 215 switch int64(0) { 216 case ms % factors["y"]: 217 unit = "y" 218 case ms % factors["w"]: 219 unit = "w" 220 case ms % factors["d"]: 221 unit = "d" 222 case ms % factors["h"]: 223 unit = "h" 224 case ms % factors["m"]: 225 unit = "m" 226 case ms % factors["s"]: 227 unit = "s" 228 } 229 return fmt.Sprintf("%v%v", ms/factors[unit], unit) 230} 231 232// MarshalYAML implements the yaml.Marshaler interface. 233func (d Duration) MarshalYAML() (interface{}, error) { 234 return d.String(), nil 235} 236 237// UnmarshalYAML implements the yaml.Unmarshaler interface. 238func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error { 239 var s string 240 if err := unmarshal(&s); err != nil { 241 return err 242 } 243 dur, err := ParseDuration(s) 244 if err != nil { 245 return err 246 } 247 *d = dur 248 return nil 249} 250