From df7d3c55edb21cda9dcc3f9ab117901c74a9f709 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Fri, 23 Feb 2024 00:54:20 +0200 Subject: [PATCH] lib/promutils: hide the math.Round() logic inside ParseTimeMsec() function This should prevent from bugs similar to https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5801 in the future This is a follow-up for ce3ec3ff2ec590aee0604bd6905f7d57dfc2a813 --- app/vmctl/time.go | 4 +--- lib/httputils/time.go | 3 +-- lib/promutils/time.go | 14 ++++++++++---- lib/promutils/time_test.go | 8 ++++---- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/vmctl/time.go b/app/vmctl/time.go index 55652475c..e4c5f03ff 100644 --- a/app/vmctl/time.go +++ b/app/vmctl/time.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "math" "time" "github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils" @@ -15,11 +14,10 @@ const ( ) func parseTime(s string) (time.Time, error) { - secs, err := promutils.ParseTime(s) + msecs, err := promutils.ParseTimeMsec(s) if err != nil { return time.Time{}, fmt.Errorf("cannot parse %s: %w", s, err) } - msecs := int64(math.Round(secs * 1e3)) if msecs < minTimeMsecs { msecs = 0 } diff --git a/lib/httputils/time.go b/lib/httputils/time.go index 0ad156575..f3e3b383e 100644 --- a/lib/httputils/time.go +++ b/lib/httputils/time.go @@ -28,11 +28,10 @@ func GetTime(r *http.Request, argKey string, defaultMs int64) (int64, error) { return maxTimeMsecs, nil } // Parse argValue - secs, err := promutils.ParseTime(argValue) + msecs, err := promutils.ParseTimeMsec(argValue) if err != nil { return 0, fmt.Errorf("cannot parse %s=%s: %w", argKey, argValue, err) } - msecs := int64(math.Round(secs * 1e3)) if msecs < minTimeMsecs { msecs = 0 } diff --git a/lib/promutils/time.go b/lib/promutils/time.go index 5b999c27f..8ec51dc85 100644 --- a/lib/promutils/time.go +++ b/lib/promutils/time.go @@ -2,19 +2,25 @@ package promutils import ( "fmt" + "math" "strconv" "strings" "time" ) -// ParseTime parses time s in different formats. +// ParseTimeMsec parses time s in different formats. // // See https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#timestamp-formats // -// It returns unix timestamp in seconds. -func ParseTime(s string) (float64, error) { +// It returns unix timestamp in milliseconds. +func ParseTimeMsec(s string) (int64, error) { currentTimestamp := float64(time.Now().UnixNano()) / 1e9 - return ParseTimeAt(s, currentTimestamp) + secs, err := ParseTimeAt(s, currentTimestamp) + if err != nil { + return 0, err + } + msecs := int64(math.Round(secs * 1000)) + return msecs, nil } const ( diff --git a/lib/promutils/time_test.go b/lib/promutils/time_test.go index 38934eea4..9ce9c9a6c 100644 --- a/lib/promutils/time_test.go +++ b/lib/promutils/time_test.go @@ -78,12 +78,12 @@ func TestParseTimeAtSuccess(t *testing.T) { f("2023-05-20T04:57:43.123456789-02:30", now, 1.6845676631234567e+09) } -func TestParseTimeFailure(t *testing.T) { +func TestParseTimeMsecFailure(t *testing.T) { f := func(s string) { t.Helper() - ts, err := ParseTime(s) - if ts != 0 { - t.Fatalf("unexpected time parsed: %f; want 0", ts) + msec, err := ParseTimeMsec(s) + if msec != 0 { + t.Fatalf("unexpected time parsed: %d; want 0", msec) } if err == nil { t.Fatalf("expecting non-nil error")