From 2dd850c9ef227d4df57be75620b7f35bfa6c2e39 Mon Sep 17 00:00:00 2001 From: Grigory Zubankov Date: Wed, 24 Oct 2018 14:37:00 +0300 Subject: [PATCH] fix: incorrect parsing of UNIX nanoseconds --- time_parse.go | 34 +++++++++++++++++----------------- time_parse_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 17 deletions(-) create mode 100644 time_parse_test.go diff --git a/time_parse.go b/time_parse.go index d0a60a1..83bca4f 100644 --- a/time_parse.go +++ b/time_parse.go @@ -1,7 +1,6 @@ package humanlog import ( - "math" "time" ) @@ -24,18 +23,19 @@ var formats = []string{ time.StampNano, } -func parseTimeFloat64(value float64) (time.Time, bool) { - if value/math.Pow10(15) > 1 { // Nanoseconds - secs := int64(math.Trunc(value / math.Pow10(6))) - nsecs := int64(math.Mod(value, math.Pow10(6))) - return time.Unix(secs, nsecs), true - } else if value/math.Pow10(12) > 1 { // Milliseconds - secs := int64(math.Trunc(value / math.Pow10(3))) - nsecs := int64(math.Mod(value, math.Pow10(3))) * int64(math.Pow10(3)) - return time.Unix(secs, nsecs), true - } else { - return time.Unix(int64(value), 0), true +func parseTimeFloat64(value float64) time.Time { + v := int64(value) + switch { + case v > 1e18: + case v > 1e15: + v *= 1e3 + case v > 1e12: + v *= 1e6 + default: + return time.Unix(v, 0) } + + return time.Unix(v/1e9, v%1e9) } // tries to parse time using a couple of formats before giving up @@ -51,15 +51,15 @@ func tryParseTime(value interface{}) (time.Time, bool) { } } case float32: - return parseTimeFloat64(float64(value.(float32))) + return parseTimeFloat64(float64(value.(float32))), true case float64: - return parseTimeFloat64(value.(float64)) + return parseTimeFloat64(value.(float64)), true case int: - return parseTimeFloat64(float64(value.(int))) + return parseTimeFloat64(float64(value.(int))), true case int32: - return parseTimeFloat64(float64(value.(int32))) + return parseTimeFloat64(float64(value.(int32))), true case int64: - return parseTimeFloat64(float64(value.(int64))) + return parseTimeFloat64(float64(value.(int64))), true } return t, false } diff --git a/time_parse_test.go b/time_parse_test.go new file mode 100644 index 0000000..ac7ee49 --- /dev/null +++ b/time_parse_test.go @@ -0,0 +1,36 @@ +package humanlog + +import ( + "testing" +) + +func TestTimeParseFloat64(t *testing.T) { + t.Run("nanoseconds", func(t *testing.T) { + golden := float64(1540369190466951764) + tm := parseTimeFloat64(golden) + if int64(golden) != tm.UnixNano() { + t.Fatal(tm.UnixNano()) + } + }) + t.Run("microseconds", func(t *testing.T) { + golden := float64(1540369190466951) + tm := parseTimeFloat64(golden) + if int64(golden)*1e3 != tm.UnixNano() { + t.Fatal(tm.UnixNano()) + } + }) + t.Run("milliseconds", func(t *testing.T) { + golden := float64(1540369190466) + tm := parseTimeFloat64(golden) + if int64(golden)*1e6 != tm.UnixNano() { + t.Fatal(tm.UnixNano()) + } + }) + t.Run("seconds", func(t *testing.T) { + golden := float64(1540369190) + tm := parseTimeFloat64(golden) + if int64(golden)*1e9 != tm.UnixNano() { + t.Fatal(tm.UnixNano()) + } + }) +}