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 an 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 166// Set implements pflag/flag.Value 167func (d *Duration) Set(s string) error { 168 var err error 169 *d, err = ParseDuration(s) 170 return err 171} 172 173// Type implements pflag.Value 174func (d *Duration) Type() string { 175 return "duration" 176} 177 178var durationRE = regexp.MustCompile("^([0-9]+)(y|w|d|h|m|s|ms)$") 179 180// ParseDuration parses a string into a time.Duration, assuming that a year 181// always has 365d, a week always has 7d, and a day always has 24h. 182func ParseDuration(durationStr string) (Duration, error) { 183 matches := durationRE.FindStringSubmatch(durationStr) 184 if len(matches) != 3 { 185 return 0, fmt.Errorf("not a valid duration string: %q", durationStr) 186 } 187 var ( 188 n, _ = strconv.Atoi(matches[1]) 189 dur = time.Duration(n) * time.Millisecond 190 ) 191 switch unit := matches[2]; unit { 192 case "y": 193 dur *= 1000 * 60 * 60 * 24 * 365 194 case "w": 195 dur *= 1000 * 60 * 60 * 24 * 7 196 case "d": 197 dur *= 1000 * 60 * 60 * 24 198 case "h": 199 dur *= 1000 * 60 * 60 200 case "m": 201 dur *= 1000 * 60 202 case "s": 203 dur *= 1000 204 case "ms": 205 // Value already correct 206 default: 207 return 0, fmt.Errorf("invalid time unit in duration string: %q", unit) 208 } 209 return Duration(dur), nil 210} 211 212func (d Duration) String() string { 213 var ( 214 ms = int64(time.Duration(d) / time.Millisecond) 215 unit = "ms" 216 ) 217 if ms == 0 { 218 return "0s" 219 } 220 factors := map[string]int64{ 221 "y": 1000 * 60 * 60 * 24 * 365, 222 "w": 1000 * 60 * 60 * 24 * 7, 223 "d": 1000 * 60 * 60 * 24, 224 "h": 1000 * 60 * 60, 225 "m": 1000 * 60, 226 "s": 1000, 227 "ms": 1, 228 } 229 230 switch int64(0) { 231 case ms % factors["y"]: 232 unit = "y" 233 case ms % factors["w"]: 234 unit = "w" 235 case ms % factors["d"]: 236 unit = "d" 237 case ms % factors["h"]: 238 unit = "h" 239 case ms % factors["m"]: 240 unit = "m" 241 case ms % factors["s"]: 242 unit = "s" 243 } 244 return fmt.Sprintf("%v%v", ms/factors[unit], unit) 245} 246 247// MarshalYAML implements the yaml.Marshaler interface. 248func (d Duration) MarshalYAML() (interface{}, error) { 249 return d.String(), nil 250} 251 252// UnmarshalYAML implements the yaml.Unmarshaler interface. 253func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error { 254 var s string 255 if err := unmarshal(&s); err != nil { 256 return err 257 } 258 dur, err := ParseDuration(s) 259 if err != nil { 260 return err 261 } 262 *d = dur 263 return nil 264} 265