From 589326a0a719d53c81398988d144d551de8c8f18 Mon Sep 17 00:00:00 2001 From: ccoVeille <3875889+ccoVeille@users.noreply.github.com> Date: Tue, 21 Jan 2025 23:36:23 +0100 Subject: [PATCH] Fix negative duration parsing Only the one the negative one that could be parsed with strconv.ParseDuration were working. Now all negative durations are working. --- duration.go | 13 +++++++++++-- duration_test.go | 14 ++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/duration.go b/duration.go index 6284b82..75d0859 100644 --- a/duration.go +++ b/duration.go @@ -56,7 +56,7 @@ var ( "w": 7 * 24 * time.Hour, } - durationMatcher = regexp.MustCompile(`((\d+)\s*([A-Za-zµ]+))`) + durationMatcher = regexp.MustCompile(`(((?:-\s?)?\d+)\s*([A-Za-zµ]+))`) ) // IsDuration returns true if the provided string is a valid duration @@ -98,10 +98,19 @@ func ParseDuration(cand string) (time.Duration, error) { ok := false for _, match := range durationMatcher.FindAllStringSubmatch(cand, -1) { - factor, err := strconv.Atoi(match[2]) // converts string to int + // remove possible leading - and spaces + value, negative := strings.CutPrefix(match[2], "-") + + // if the string is a valid duration, parse it + factor, err := strconv.Atoi(strings.TrimSpace(value)) // converts string to int if err != nil { return 0, err } + + if negative { + factor = -factor + } + unit := strings.ToLower(strings.TrimSpace(match[3])) for _, variants := range timeUnits { diff --git a/duration_test.go b/duration_test.go index 75562d2..cfee1bc 100644 --- a/duration_test.go +++ b/duration_test.go @@ -123,7 +123,6 @@ func TestDurationScanner_Nil(t *testing.T) { func TestDurationParser(t *testing.T) { testcases := map[string]time.Duration{ - // parse the short forms without spaces "1ns": 1 * time.Nanosecond, "1us": 1 * time.Microsecond, @@ -182,10 +181,18 @@ func TestDurationParser(t *testing.T) { } for str, dur := range testcases { - testDurationParser(t, str, dur) - testDurationSQLScanner(t, dur) + t.Run(str, func(t *testing.T) { + testDurationParser(t, str, dur) + + // negative duration + testDurationParser(t, "-"+str, -dur) + testDurationParser(t, "- "+str, -dur) + + testDurationSQLScanner(t, dur) + }) } } + func TestIsDuration_Caveats(t *testing.T) { // This works too e := IsDuration("45 weeks") @@ -206,7 +213,6 @@ func TestIsDuration_Caveats(t *testing.T) { // This does not work e = IsDuration("12 phours") assert.False(t, e) - } func TestDeepCopyDuration(t *testing.T) {