github.com/thanos-io/thanos@v0.32.5/internal/cortex/util/time.go (about)

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