Skip to content

Commit 7bd9fd5

Browse files
authored
Merge pull request #124 from quickwit-oss/ddelemeny/improve-parsetime-error
Improve ParseTime, handle mismatched format and value
2 parents 8afe6fb + 8c6eafb commit 7bd9fd5

File tree

2 files changed

+51
-38
lines changed

2 files changed

+51
-38
lines changed

pkg/utils/parse_time.go

+43-38
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package utils
22

33
import (
4-
"errors"
54
"fmt"
65
"reflect"
76
"time"
@@ -26,33 +25,44 @@ const Rfc2822zLayout string = "%a, %d %b %Y %T %z"
2625
// Parses a value into Time given a timeOutputFormat. The conversion
2726
// only works with float64 as this is what we get when parsing a response.
2827
func ParseTime(value any, timeOutputFormat string) (time.Time, error) {
29-
switch timeOutputFormat {
30-
case Iso8601, Rfc3339:
28+
switch value.(type) {
29+
case string:
3130
value_string := value.(string)
32-
timeValue, err := time.Parse(time.RFC3339, value_string)
33-
if err != nil {
34-
return time.Time{}, err
35-
}
36-
return timeValue, nil
31+
switch timeOutputFormat {
32+
case Iso8601, Rfc3339:
33+
timeValue, err := time.Parse(time.RFC3339, value_string)
34+
if err != nil {
35+
return time.Time{}, err
36+
}
37+
return timeValue, nil
3738

38-
case Rfc2822:
39-
// XXX: the time package's layout for RFC2822 is bogus, don't use that.
40-
value_string := value.(string)
41-
timeValue, err := timefmt.Parse(value_string, Rfc2822Layout)
42-
if err != nil {
43-
return time.Time{}, err
44-
}
45-
return timeValue, nil
46-
case Rfc2822z:
47-
// XXX: the time package's layout for RFC2822 is bogus, don't use that.
48-
value_string := value.(string)
49-
timeValue, err := timefmt.Parse(value_string, Rfc2822zLayout)
50-
if err != nil {
51-
return time.Time{}, err
52-
}
53-
return timeValue, nil
39+
case Rfc2822:
40+
// XXX: the time package's layout for RFC2822 is bogus, don't use that.
41+
timeValue, err := timefmt.Parse(value_string, Rfc2822Layout)
42+
if err != nil {
43+
return time.Time{}, err
44+
}
45+
return timeValue, nil
46+
47+
case Rfc2822z:
48+
// XXX: the time package's layout for RFC2822 is bogus, don't use that.
49+
timeValue, err := timefmt.Parse(value_string, Rfc2822zLayout)
50+
if err != nil {
51+
return time.Time{}, err
52+
}
53+
return timeValue, nil
54+
55+
case TimestampSecs, TimestampMillis, TimestampMicros, TimestampNanos:
56+
return time.Time{}, fmt.Errorf("ParseTime received incoherent inputs: timeOutputFormat: %s value: %s (%s)", timeOutputFormat, fmt.Sprint(value), reflect.TypeOf(value))
5457

55-
case TimestampSecs, TimestampMillis, TimestampMicros, TimestampNanos:
58+
default:
59+
timeValue, err := timefmt.Parse(value_string, timeOutputFormat)
60+
if err != nil {
61+
return time.Time{}, err
62+
}
63+
return timeValue, nil
64+
}
65+
default:
5666
var value_i64 int64
5767
switch value.(type) {
5868
case int, int8, int16, int32, int64:
@@ -61,25 +71,20 @@ func ParseTime(value any, timeOutputFormat string) (time.Time, error) {
6171
value_f64 := reflect.ValueOf(value).Float()
6272
value_i64 = int64(value_f64)
6373
default:
64-
return time.Time{}, errors.New("parseTime only accepts float64 or int64 values with timestamp based formats")
74+
return time.Time{}, fmt.Errorf("ParseTime does not support values of type (%s)", reflect.TypeOf(value))
6575
}
6676

67-
if timeOutputFormat == TimestampSecs {
77+
switch timeOutputFormat {
78+
case TimestampSecs:
6879
return time.Unix(value_i64, 0), nil
69-
} else if timeOutputFormat == TimestampMillis {
80+
case TimestampMillis:
7081
return time.Unix(0, value_i64*1_000_000), nil
71-
} else if timeOutputFormat == TimestampMicros {
82+
case TimestampMicros:
7283
return time.Unix(0, value_i64*1_000), nil
73-
} else if timeOutputFormat == TimestampNanos {
84+
case TimestampNanos:
7485
return time.Unix(0, value_i64), nil
86+
default:
87+
return time.Time{}, fmt.Errorf("ParseTime received incoherent inputs: timeOutputFormat: %s value: %s (%s)", timeOutputFormat, fmt.Sprint(value), reflect.TypeOf(value))
7588
}
76-
default:
77-
value_string := value.(string)
78-
timeValue, err := timefmt.Parse(value_string, timeOutputFormat)
79-
if err != nil {
80-
return time.Time{}, err
81-
}
82-
return timeValue, nil
8389
}
84-
return time.Time{}, fmt.Errorf("timeOutputFormat not supported yet %s", timeOutputFormat)
8590
}

pkg/utils/parse_time_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,12 @@ func TestParseTime(t *testing.T) {
7171
}
7272
})
7373
}
74+
75+
t.Run("Error on incoherent format and value", func(t *testing.T) {
76+
value := 1711629296987654321
77+
format := "%Y-%m-%d %H:%M:%S.%f"
78+
_, err := ParseTime(value, format)
79+
80+
assert.ErrorContains(err, fmt.Sprintf("ParseTime received incoherent inputs: timeOutputFormat: %s value: %s (%s)", format, fmt.Sprint(value), "int"))
81+
})
7482
}

0 commit comments

Comments
 (0)