github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/util/time.go (about) 1 package util 2 3 import ( 4 "math" 5 "math/rand" 6 "net/http" 7 "strconv" 8 "time" 9 10 "github.com/prometheus/common/model" 11 "github.com/weaveworks/common/httpgrpc" 12 ) 13 14 const ( 15 nanosecondsInMillisecond = int64(time.Millisecond / time.Nanosecond) 16 ) 17 18 func TimeToMillis(t time.Time) int64 { 19 return t.UnixNano() / nanosecondsInMillisecond 20 } 21 22 // TimeFromMillis is a helper to turn milliseconds -> time.Time 23 func TimeFromMillis(ms int64) time.Time { 24 return time.Unix(0, ms*nanosecondsInMillisecond) 25 } 26 27 // FormatTimeMillis returns a human readable version of the input time (in milliseconds). 28 func FormatTimeMillis(ms int64) string { 29 return TimeFromMillis(ms).String() 30 } 31 32 // FormatTimeModel returns a human readable version of the input time. 33 func FormatTimeModel(t model.Time) string { 34 return TimeFromMillis(int64(t)).String() 35 } 36 37 // ParseTime parses the string into an int64, milliseconds since epoch. 38 func ParseTime(s string) (int64, error) { 39 if t, err := strconv.ParseFloat(s, 64); err == nil { 40 s, ns := math.Modf(t) 41 ns = math.Round(ns*1000) / 1000 42 tm := time.Unix(int64(s), int64(ns*float64(time.Second))) 43 return TimeToMillis(tm), nil 44 } 45 if t, err := time.Parse(time.RFC3339Nano, s); err == nil { 46 return TimeToMillis(t), nil 47 } 48 return 0, httpgrpc.Errorf(http.StatusBadRequest, "cannot parse %q to a valid timestamp", s) 49 } 50 51 // DurationWithJitter returns random duration from "input - input*variance" to "input + input*variance" interval. 52 func DurationWithJitter(input time.Duration, variancePerc float64) time.Duration { 53 // No duration? No jitter. 54 if input == 0 { 55 return 0 56 } 57 58 variance := int64(float64(input) * variancePerc) 59 jitter := rand.Int63n(variance*2) - variance 60 61 return input + time.Duration(jitter) 62 } 63 64 // DurationWithPositiveJitter returns random duration from "input" to "input + input*variance" interval. 65 func DurationWithPositiveJitter(input time.Duration, variancePerc float64) time.Duration { 66 // No duration? No jitter. 67 if input == 0 { 68 return 0 69 } 70 71 variance := int64(float64(input) * variancePerc) 72 jitter := rand.Int63n(variance) 73 74 return input + time.Duration(jitter) 75 } 76 77 // NewDisableableTicker essentially wraps NewTicker but allows the ticker to be disabled by passing 78 // zero duration as the interval. Returns a function for stopping the ticker, and the ticker channel. 79 func NewDisableableTicker(interval time.Duration) (func(), <-chan time.Time) { 80 if interval == 0 { 81 return func() {}, nil 82 } 83 84 tick := time.NewTicker(interval) 85 return func() { tick.Stop() }, tick.C 86 }