...

Source file src/github.com/prometheus/common/model/time.go

Documentation: github.com/prometheus/common/model

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

View as plain text