time_range.go 2.8 KB
Newer Older
1 2 3
package tsdb

import (
4
	"strconv"
5 6
	"strings"
	"time"
7 8

	"github.com/timberio/go-datemath"
9 10
)

11 12
func NewTimeRange(from, to string) *TimeRange {
	return &TimeRange{
13 14
		From: from,
		To:   to,
15
		now:  time.Now(),
16 17 18
	}
}

19 20 21 22 23 24 25 26
func NewFakeTimeRange(from, to string, now time.Time) *TimeRange {
	return &TimeRange{
		From: from,
		To:   to,
		now:  now,
	}
}

27 28 29
type TimeRange struct {
	From string
	To   string
30
	now  time.Time
31 32
}

33 34 35 36
func (tr *TimeRange) GetFromAsMsEpoch() int64 {
	return tr.MustGetFrom().UnixNano() / int64(time.Millisecond)
}

37 38 39 40
func (tr *TimeRange) GetFromAsSecondsEpoch() int64 {
	return tr.GetFromAsMsEpoch() / 1000
}

41 42 43 44
func (tr *TimeRange) GetFromAsTimeUTC() time.Time {
	return tr.MustGetFrom().UTC()
}

45 46 47 48
func (tr *TimeRange) GetToAsMsEpoch() int64 {
	return tr.MustGetTo().UnixNano() / int64(time.Millisecond)
}

49 50 51 52
func (tr *TimeRange) GetToAsSecondsEpoch() int64 {
	return tr.GetToAsMsEpoch() / 1000
}

53 54 55 56
func (tr *TimeRange) GetToAsTimeUTC() time.Time {
	return tr.MustGetTo().UTC()
}

57
func (tr *TimeRange) MustGetFrom() time.Time {
58 59
	res, err := tr.ParseFrom()
	if err != nil {
60
		return time.Unix(0, 0)
61
	}
62
	return res
63
}
64

65
func (tr *TimeRange) MustGetTo() time.Time {
66 67
	res, err := tr.ParseTo()
	if err != nil {
68 69
		return time.Unix(0, 0)
	}
70
	return res
71 72 73 74 75 76 77 78 79 80
}

func tryParseUnixMsEpoch(val string) (time.Time, bool) {
	if val, err := strconv.ParseInt(val, 10, 64); err == nil {
		seconds := val / 1000
		nano := (val - seconds*1000) * 1000000
		return time.Unix(seconds, nano), true
	}
	return time.Time{}, false
}
81

82
func (tr *TimeRange) ParseFrom() (time.Time, error) {
83
	return parse(tr.From, tr.now, false, nil)
84 85
}

86
func (tr *TimeRange) ParseTo() (time.Time, error) {
87
	return parse(tr.To, tr.now, true, nil)
88
}
89

90 91 92 93 94 95 96 97 98
func (tr *TimeRange) ParseFromWithLocation(location *time.Location) (time.Time, error) {
	return parse(tr.From, tr.now, false, location)
}

func (tr *TimeRange) ParseToWithLocation(location *time.Location) (time.Time, error) {
	return parse(tr.To, tr.now, true, location)
}

func parse(s string, now time.Time, withRoundUp bool, location *time.Location) (time.Time, error) {
99 100
	if res, ok := tryParseUnixMsEpoch(s); ok {
		return res, nil
101 102
	}

103
	diff, err := time.ParseDuration("-" + s)
104
	if err != nil {
105 106 107 108 109 110 111 112 113
		options := []func(*datemath.Options){
			datemath.WithNow(now),
			datemath.WithRoundUp(withRoundUp),
		}
		if location != nil {
			options = append(options, datemath.WithLocation(location))
		}

		return datemath.ParseAndEvaluate(s, options...)
114 115
	}

116
	return now.Add(diff), nil
117
}
118 119 120 121

// EpochPrecisionToMs converts epoch precision to millisecond, if needed.
// Only seconds to milliseconds supported right now
func EpochPrecisionToMs(value float64) float64 {
122 123 124
	s := strconv.FormatFloat(value, 'e', -1, 64)
	if strings.HasSuffix(s, "e+09") {
		return value * float64(1e3)
125 126
	}

127 128
	if strings.HasSuffix(s, "e+18") {
		return value / float64(time.Millisecond)
129 130
	}

131
	return value
132
}