cubefs
317 строк · 7.9 Кб
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 model15
16import (17"encoding/json"18"errors"19"fmt"20"math"21"regexp"22"strconv"23"strings"24"time"25)
26
27const (28// MinimumTick is the minimum supported time resolution. This has to be29// at least time.Second in order for the code below to work.30minimumTick = time.Millisecond31// second is the Time duration equivalent to one second.32second = int64(time.Second / minimumTick)33// The number of nanoseconds per minimum tick.34nanosPerTick = int64(minimumTick / time.Nanosecond)35
36// Earliest is the earliest Time representable. Handy for37// initializing a high watermark.38Earliest = Time(math.MinInt64)39// Latest is the latest Time representable. Handy for initializing40// a low watermark.41Latest = Time(math.MaxInt64)42)
43
44// Time is the number of milliseconds since the epoch
45// (1970-01-01 00:00 UTC) excluding leap seconds.
46type Time int6447
48// Interval describes an interval between two timestamps.
49type Interval struct {50Start, End Time51}
52
53// Now returns the current time as a Time.
54func Now() Time {55return TimeFromUnixNano(time.Now().UnixNano())56}
57
58// TimeFromUnix returns the Time equivalent to the Unix Time t
59// provided in seconds.
60func TimeFromUnix(t int64) Time {61return Time(t * second)62}
63
64// TimeFromUnixNano returns the Time equivalent to the Unix Time
65// t provided in nanoseconds.
66func TimeFromUnixNano(t int64) Time {67return Time(t / nanosPerTick)68}
69
70// Equal reports whether two Times represent the same instant.
71func (t Time) Equal(o Time) bool {72return t == o73}
74
75// Before reports whether the Time t is before o.
76func (t Time) Before(o Time) bool {77return t < o78}
79
80// After reports whether the Time t is after o.
81func (t Time) After(o Time) bool {82return t > o83}
84
85// Add returns the Time t + d.
86func (t Time) Add(d time.Duration) Time {87return t + Time(d/minimumTick)88}
89
90// Sub returns the Duration t - o.
91func (t Time) Sub(o Time) time.Duration {92return time.Duration(t-o) * minimumTick93}
94
95// Time returns the time.Time representation of t.
96func (t Time) Time() time.Time {97return time.Unix(int64(t)/second, (int64(t)%second)*nanosPerTick)98}
99
100// Unix returns t as a Unix time, the number of seconds elapsed
101// since January 1, 1970 UTC.
102func (t Time) Unix() int64 {103return int64(t) / second104}
105
106// UnixNano returns t as a Unix time, the number of nanoseconds elapsed
107// since January 1, 1970 UTC.
108func (t Time) UnixNano() int64 {109return int64(t) * nanosPerTick110}
111
112// The number of digits after the dot.
113var dotPrecision = int(math.Log10(float64(second)))114
115// String returns a string representation of the Time.
116func (t Time) String() string {117return strconv.FormatFloat(float64(t)/float64(second), 'f', -1, 64)118}
119
120// MarshalJSON implements the json.Marshaler interface.
121func (t Time) MarshalJSON() ([]byte, error) {122return []byte(t.String()), nil123}
124
125// UnmarshalJSON implements the json.Unmarshaler interface.
126func (t *Time) UnmarshalJSON(b []byte) error {127p := strings.Split(string(b), ".")128switch len(p) {129case 1:130v, err := strconv.ParseInt(string(p[0]), 10, 64)131if err != nil {132return err133}134*t = Time(v * second)135
136case 2:137v, err := strconv.ParseInt(string(p[0]), 10, 64)138if err != nil {139return err140}141v *= second142
143prec := dotPrecision - len(p[1])144if prec < 0 {145p[1] = p[1][:dotPrecision]146} else if prec > 0 {147p[1] = p[1] + strings.Repeat("0", prec)148}149
150va, err := strconv.ParseInt(p[1], 10, 32)151if err != nil {152return err153}154
155// If the value was something like -0.1 the negative is lost in the156// parsing because of the leading zero, this ensures that we capture it.157if len(p[0]) > 0 && p[0][0] == '-' && v+va > 0 {158*t = Time(v+va) * -1159} else {160*t = Time(v + va)161}162
163default:164return fmt.Errorf("invalid time %q", string(b))165}166return nil167}
168
169// Duration wraps time.Duration. It is used to parse the custom duration format
170// from YAML.
171// This type should not propagate beyond the scope of input/output processing.
172type Duration time.Duration173
174// Set implements pflag/flag.Value
175func (d *Duration) Set(s string) error {176var err error177*d, err = ParseDuration(s)178return err179}
180
181// Type implements pflag.Value
182func (d *Duration) Type() string {183return "duration"184}
185
186var durationRE = regexp.MustCompile("^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$")187
188// ParseDuration parses a string into a time.Duration, assuming that a year
189// always has 365d, a week always has 7d, and a day always has 24h.
190func ParseDuration(durationStr string) (Duration, error) {191switch durationStr {192case "0":193// Allow 0 without a unit.194return 0, nil195case "":196return 0, errors.New("empty duration string")197}198matches := durationRE.FindStringSubmatch(durationStr)199if matches == nil {200return 0, fmt.Errorf("not a valid duration string: %q", durationStr)201}202var dur time.Duration203
204// Parse the match at pos `pos` in the regex and use `mult` to turn that205// into ms, then add that value to the total parsed duration.206var overflowErr error207m := func(pos int, mult time.Duration) {208if matches[pos] == "" {209return210}211n, _ := strconv.Atoi(matches[pos])212
213// Check if the provided duration overflows time.Duration (> ~ 290years).214if n > int((1<<63-1)/mult/time.Millisecond) {215overflowErr = errors.New("duration out of range")216}217d := time.Duration(n) * time.Millisecond218dur += d * mult219
220if dur < 0 {221overflowErr = errors.New("duration out of range")222}223}224
225m(2, 1000*60*60*24*365) // y226m(4, 1000*60*60*24*7) // w227m(6, 1000*60*60*24) // d228m(8, 1000*60*60) // h229m(10, 1000*60) // m230m(12, 1000) // s231m(14, 1) // ms232
233return Duration(dur), overflowErr234}
235
236func (d Duration) String() string {237var (238ms = int64(time.Duration(d) / time.Millisecond)239r = ""240)241if ms == 0 {242return "0s"243}244
245f := func(unit string, mult int64, exact bool) {246if exact && ms%mult != 0 {247return248}249if v := ms / mult; v > 0 {250r += fmt.Sprintf("%d%s", v, unit)251ms -= v * mult252}253}254
255// Only format years and weeks if the remainder is zero, as it is often256// easier to read 90d than 12w6d.257f("y", 1000*60*60*24*365, true)258f("w", 1000*60*60*24*7, true)259
260f("d", 1000*60*60*24, false)261f("h", 1000*60*60, false)262f("m", 1000*60, false)263f("s", 1000, false)264f("ms", 1, false)265
266return r267}
268
269// MarshalJSON implements the json.Marshaler interface.
270func (d Duration) MarshalJSON() ([]byte, error) {271return json.Marshal(d.String())272}
273
274// UnmarshalJSON implements the json.Unmarshaler interface.
275func (d *Duration) UnmarshalJSON(bytes []byte) error {276var s string277if err := json.Unmarshal(bytes, &s); err != nil {278return err279}280dur, err := ParseDuration(s)281if err != nil {282return err283}284*d = dur285return nil286}
287
288// MarshalText implements the encoding.TextMarshaler interface.
289func (d *Duration) MarshalText() ([]byte, error) {290return []byte(d.String()), nil291}
292
293// UnmarshalText implements the encoding.TextUnmarshaler interface.
294func (d *Duration) UnmarshalText(text []byte) error {295var err error296*d, err = ParseDuration(string(text))297return err298}
299
300// MarshalYAML implements the yaml.Marshaler interface.
301func (d Duration) MarshalYAML() (interface{}, error) {302return d.String(), nil303}
304
305// UnmarshalYAML implements the yaml.Unmarshaler interface.
306func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error {307var s string308if err := unmarshal(&s); err != nil {309return err310}311dur, err := ParseDuration(s)312if err != nil {313return err314}315*d = dur316return nil317}
318