mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Core: use go-datemath in timerange utility (#23120)
* Core: use go-datemath in time_range * Core: update timerange for negative epoch * Core: update gtime component * Core: clean up time_range tests * Update pkg/components/gtime/gtime.go Co-Authored-By: Arve Knudsen <arve.knudsen@gmail.com> * Core: clean gtime tests * components/gtime: Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
parent
69bdcccd10
commit
56687a08f9
@ -1,12 +1,13 @@
|
||||
package gtime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var dateUnitPattern = regexp.MustCompile(`(\d+)([wdy])`)
|
||||
var dateUnitPattern = regexp.MustCompile(`^(\d+)([dwMy])$`)
|
||||
|
||||
// ParseInterval parses an interval with support for all units that Grafana uses.
|
||||
func ParseInterval(interval string) (time.Duration, error) {
|
||||
@ -18,14 +19,18 @@ func ParseInterval(interval string) (time.Duration, error) {
|
||||
|
||||
num, _ := strconv.Atoi(string(result[1]))
|
||||
period := string(result[2])
|
||||
now := time.Now()
|
||||
|
||||
if period == `d` {
|
||||
return time.Hour * 24 * time.Duration(num), nil
|
||||
switch period {
|
||||
case "d":
|
||||
return now.Sub(now.AddDate(0, 0, -num)), nil
|
||||
case "w":
|
||||
return now.Sub(now.AddDate(0, 0, -num*7)), nil
|
||||
case "M":
|
||||
return now.Sub(now.AddDate(0, -num, 0)), nil
|
||||
case "y":
|
||||
return now.Sub(now.AddDate(-num, 0, 0)), nil
|
||||
}
|
||||
|
||||
if period == `w` {
|
||||
return time.Hour * 24 * 7 * time.Duration(num), nil
|
||||
}
|
||||
|
||||
return time.Hour * 24 * 7 * 365 * time.Duration(num), nil
|
||||
return 0, fmt.Errorf("ParseInterval: invalid duration %q", interval)
|
||||
}
|
||||
|
@ -1,35 +1,38 @@
|
||||
package gtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseInterval(t *testing.T) {
|
||||
now := time.Now()
|
||||
|
||||
tcs := []struct {
|
||||
interval string
|
||||
duration time.Duration
|
||||
err error
|
||||
err string
|
||||
}{
|
||||
{interval: "1d", duration: time.Hour * 24},
|
||||
{interval: "1w", duration: time.Hour * 24 * 7},
|
||||
{interval: "2w", duration: time.Hour * 24 * 7 * 2},
|
||||
{interval: "1y", duration: time.Hour * 24 * 7 * 365},
|
||||
{interval: "5y", duration: time.Hour * 24 * 7 * 365 * 5},
|
||||
{interval: "1M", err: errors.New("time: unknown unit M in duration 1M")},
|
||||
{interval: "invalid-duration", err: errors.New("time: invalid duration invalid-duration")},
|
||||
{interval: "1d", duration: now.Sub(now.AddDate(0, 0, -1))},
|
||||
{interval: "1w", duration: now.Sub(now.AddDate(0, 0, -7))},
|
||||
{interval: "2w", duration: now.Sub(now.AddDate(0, 0, -14))},
|
||||
{interval: "1M", duration: now.Sub(now.AddDate(0, -1, 0))},
|
||||
{interval: "1y", duration: now.Sub(now.AddDate(-1, 0, 0))},
|
||||
{interval: "5y", duration: now.Sub(now.AddDate(-5, 0, 0))},
|
||||
{interval: "invalid-duration", err: "time: invalid duration invalid-duration"},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
t.Run(fmt.Sprintf("testcase %d", i), func(t *testing.T) {
|
||||
res, err := ParseInterval(tc.interval)
|
||||
if err != nil && err.Error() != tc.err.Error() {
|
||||
t.Fatalf("expected '%v' got '%v'", tc.err, err)
|
||||
}
|
||||
if res != tc.duration {
|
||||
t.Errorf("expected %v got %v", tc.duration, res)
|
||||
if tc.err == "" {
|
||||
require.NoError(t, err, "interval %q", tc.interval)
|
||||
require.Equal(t, tc.duration, res, "interval %q", tc.interval)
|
||||
} else {
|
||||
require.EqualError(t, err, tc.err, "interval %q", tc.interval)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
package tsdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/timberio/go-datemath"
|
||||
)
|
||||
|
||||
func NewTimeRange(from, to string) *TimeRange {
|
||||
@ -79,38 +80,26 @@ func tryParseUnixMsEpoch(val string) (time.Time, bool) {
|
||||
}
|
||||
|
||||
func (tr *TimeRange) ParseFrom() (time.Time, error) {
|
||||
if res, ok := tryParseUnixMsEpoch(tr.From); ok {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
fromRaw := strings.Replace(tr.From, "now-", "", 1)
|
||||
diff, err := time.ParseDuration("-" + fromRaw)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
return tr.now.Add(diff), nil
|
||||
return parse(tr.From, tr.now, false)
|
||||
}
|
||||
|
||||
func (tr *TimeRange) ParseTo() (time.Time, error) {
|
||||
if tr.To == "now" {
|
||||
return tr.now, nil
|
||||
} else if strings.HasPrefix(tr.To, "now-") {
|
||||
withoutNow := strings.Replace(tr.To, "now-", "", 1)
|
||||
return parse(tr.To, tr.now, true)
|
||||
}
|
||||
|
||||
diff, err := time.ParseDuration("-" + withoutNow)
|
||||
if err != nil {
|
||||
return time.Time{}, nil
|
||||
}
|
||||
|
||||
return tr.now.Add(diff), nil
|
||||
}
|
||||
|
||||
if res, ok := tryParseUnixMsEpoch(tr.To); ok {
|
||||
func parse(s string, now time.Time, withRoundUp bool) (time.Time, error) {
|
||||
if res, ok := tryParseUnixMsEpoch(s); ok {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
return time.Time{}, fmt.Errorf("cannot parse to value %s", tr.To)
|
||||
withoutNow := strings.Replace(s, "now-", "", 1)
|
||||
|
||||
diff, err := time.ParseDuration("-" + withoutNow)
|
||||
if err != nil {
|
||||
return datemath.ParseAndEvaluate(s, datemath.WithNow(now), datemath.WithRoundUp(withRoundUp))
|
||||
}
|
||||
|
||||
return now.Add(diff), nil
|
||||
}
|
||||
|
||||
// EpochPrecisionToMs converts epoch precision to millisecond, if needed.
|
||||
|
@ -1,7 +1,9 @@
|
||||
package tsdb
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
@ -20,7 +22,8 @@ func TestTimeRange(t *testing.T) {
|
||||
}
|
||||
|
||||
Convey("5m ago ", func() {
|
||||
fiveMinAgo, _ := time.ParseDuration("-5m")
|
||||
fiveMinAgo, err := time.ParseDuration("-5m")
|
||||
So(err, ShouldBeNil)
|
||||
expected := now.Add(fiveMinAgo)
|
||||
|
||||
res, err := tr.ParseFrom()
|
||||
@ -43,7 +46,8 @@ func TestTimeRange(t *testing.T) {
|
||||
}
|
||||
|
||||
Convey("5h ago ", func() {
|
||||
fiveHourAgo, _ := time.ParseDuration("-5h")
|
||||
fiveHourAgo, err := time.ParseDuration("-5h")
|
||||
So(err, ShouldBeNil)
|
||||
expected := now.Add(fiveHourAgo)
|
||||
|
||||
res, err := tr.ParseFrom()
|
||||
@ -52,7 +56,8 @@ func TestTimeRange(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("now-10m ", func() {
|
||||
tenMinAgo, _ := time.ParseDuration("-10m")
|
||||
tenMinAgo, err := time.ParseDuration("-10m")
|
||||
So(err, ShouldBeNil)
|
||||
expected := now.Add(tenMinAgo)
|
||||
res, err := tr.ParseTo()
|
||||
So(err, ShouldBeNil)
|
||||
@ -60,7 +65,101 @@ func TestTimeRange(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
Convey("can parse unix epocs", func() {
|
||||
now, err := time.Parse(time.RFC3339Nano, "2020-03-26T15:12:56.000Z")
|
||||
So(err, ShouldBeNil)
|
||||
Convey("Can parse now-1M/M, now-1M/M", func() {
|
||||
tr := TimeRange{
|
||||
From: "now-1M/M",
|
||||
To: "now-1M/M",
|
||||
now: now,
|
||||
}
|
||||
|
||||
Convey("from now-1M/M ", func() {
|
||||
expected, err := time.Parse(time.RFC3339Nano, "2020-02-01T00:00:00.000Z")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res, err := tr.ParseFrom()
|
||||
So(err, ShouldBeNil)
|
||||
So(res, ShouldEqual, expected)
|
||||
})
|
||||
|
||||
Convey("to now-1M/M ", func() {
|
||||
expected, err := time.Parse(time.RFC3339Nano, "2020-02-29T23:59:59.999Z")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res, err := tr.ParseTo()
|
||||
So(err, ShouldBeNil)
|
||||
So(res, ShouldEqual, expected)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Can parse now-3d, now+3w", func() {
|
||||
tr := TimeRange{
|
||||
From: "now-3d",
|
||||
To: "now+3w",
|
||||
now: now,
|
||||
}
|
||||
|
||||
Convey("now-3d ", func() {
|
||||
expected, err := time.Parse(time.RFC3339Nano, "2020-03-23T15:12:56.000Z")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res, err := tr.ParseFrom()
|
||||
So(err, ShouldBeNil)
|
||||
So(res, ShouldEqual, expected)
|
||||
})
|
||||
|
||||
Convey("now+3w ", func() {
|
||||
expected, err := time.Parse(time.RFC3339Nano, "2020-04-16T15:12:56.000Z")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res, err := tr.ParseTo()
|
||||
So(err, ShouldBeNil)
|
||||
So(res, ShouldEqual, expected)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Can parse 1960-02-01T07:00:00.000Z, 1965-02-03T08:00:00.000Z", func() {
|
||||
tr := TimeRange{
|
||||
From: "1960-02-01T07:00:00.000Z",
|
||||
To: "1965-02-03T08:00:00.000Z",
|
||||
now: now,
|
||||
}
|
||||
|
||||
Convey("1960-02-01T07:00:00.000Z ", func() {
|
||||
expected, err := time.Parse(time.RFC3339Nano, "1960-02-01T07:00:00.000Z")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res, err := tr.ParseFrom()
|
||||
So(err, ShouldBeNil)
|
||||
So(res, ShouldEqual, expected)
|
||||
})
|
||||
|
||||
Convey("1965-02-03T08:00:00.000Z ", func() {
|
||||
expected, err := time.Parse(time.RFC3339Nano, "1965-02-03T08:00:00.000Z")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res, err := tr.ParseTo()
|
||||
So(err, ShouldBeNil)
|
||||
So(res, ShouldEqual, expected)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Can parse negative unix epochs", func() {
|
||||
from := time.Date(1960, 2, 1, 7, 0, 0, 0, time.UTC)
|
||||
to := time.Date(1965, 2, 3, 8, 0, 0, 0, time.UTC)
|
||||
tr := NewTimeRange(strconv.FormatInt(from.UnixNano()/int64(time.Millisecond), 10), strconv.FormatInt(to.UnixNano()/int64(time.Millisecond), 10))
|
||||
|
||||
res, err := tr.ParseFrom()
|
||||
So(err, ShouldBeNil)
|
||||
So(res, ShouldEqual, from)
|
||||
|
||||
res, err = tr.ParseTo()
|
||||
So(err, ShouldBeNil)
|
||||
So(res, ShouldEqual, to)
|
||||
})
|
||||
|
||||
Convey("can parse unix epochs", func() {
|
||||
var err error
|
||||
tr := TimeRange{
|
||||
From: "1474973725473",
|
||||
|
Loading…
Reference in New Issue
Block a user