mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-29 13:49:28 +08:00

* NOISSUE - Add timestamp transformation rules for specifc JSON fields Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add tests and defaults Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix reviews Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix Created Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix READMEs Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix Config file Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Improve the timestamp Config structure Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix typos Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix smpp Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix reviews Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Rm duplicated Unmarshal Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Extract the error var Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix review Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Return error if time field transformation fails Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
153 lines
3.5 KiB
Go
153 lines
3.5 KiB
Go
// Copyright (c) Mainflux
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package json
|
|
|
|
import (
|
|
"math"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mainflux/mainflux/pkg/errors"
|
|
)
|
|
|
|
var errUnsupportedFormat = errors.New("unsupported time format")
|
|
|
|
func parseTimestamp(format string, timestamp interface{}, location string) (time.Time, error) {
|
|
switch format {
|
|
case "unix", "unix_ms", "unix_us", "unix_ns":
|
|
return parseUnix(format, timestamp)
|
|
default:
|
|
if location == "" {
|
|
location = "UTC"
|
|
}
|
|
return parseTime(format, timestamp, location)
|
|
}
|
|
}
|
|
|
|
func parseUnix(format string, timestamp interface{}) (time.Time, error) {
|
|
integer, fractional, err := parseComponents(timestamp)
|
|
if err != nil {
|
|
return time.Unix(0, 0), err
|
|
}
|
|
|
|
switch strings.ToLower(format) {
|
|
case "unix":
|
|
return time.Unix(integer, fractional).UTC(), nil
|
|
case "unix_ms":
|
|
return time.Unix(0, integer*1e6).UTC(), nil
|
|
case "unix_us":
|
|
return time.Unix(0, integer*1e3).UTC(), nil
|
|
case "unix_ns":
|
|
return time.Unix(0, integer).UTC(), nil
|
|
default:
|
|
return time.Unix(0, 0), errUnsupportedFormat
|
|
}
|
|
}
|
|
|
|
func parseComponents(timestamp interface{}) (int64, int64, error) {
|
|
switch ts := timestamp.(type) {
|
|
case string:
|
|
parts := strings.SplitN(ts, ".", 2)
|
|
if len(parts) == 2 {
|
|
return parseUnixTimeComponents(parts[0], parts[1])
|
|
}
|
|
|
|
parts = strings.SplitN(ts, ",", 2)
|
|
if len(parts) == 2 {
|
|
return parseUnixTimeComponents(parts[0], parts[1])
|
|
}
|
|
|
|
integer, err := strconv.ParseInt(ts, 10, 64)
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
return integer, 0, nil
|
|
case int8:
|
|
return int64(ts), 0, nil
|
|
case int16:
|
|
return int64(ts), 0, nil
|
|
case int32:
|
|
return int64(ts), 0, nil
|
|
case int64:
|
|
return ts, 0, nil
|
|
case uint8:
|
|
return int64(ts), 0, nil
|
|
case uint16:
|
|
return int64(ts), 0, nil
|
|
case uint32:
|
|
return int64(ts), 0, nil
|
|
case uint64:
|
|
return int64(ts), 0, nil
|
|
case float32:
|
|
integer, fractional := math.Modf(float64(ts))
|
|
return int64(integer), int64(fractional * 1e9), nil
|
|
case float64:
|
|
integer, fractional := math.Modf(ts)
|
|
return int64(integer), int64(fractional * 1e9), nil
|
|
default:
|
|
return 0, 0, errUnsupportedFormat
|
|
}
|
|
}
|
|
|
|
func parseUnixTimeComponents(first, second string) (int64, int64, error) {
|
|
integer, err := strconv.ParseInt(first, 10, 64)
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
|
|
// Convert to nanoseconds, dropping any greater precision.
|
|
buf := []byte("000000000")
|
|
copy(buf, second)
|
|
|
|
fractional, err := strconv.ParseInt(string(buf), 10, 64)
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
return integer, fractional, nil
|
|
}
|
|
|
|
func parseTime(format string, timestamp interface{}, location string) (time.Time, error) {
|
|
switch ts := timestamp.(type) {
|
|
case string:
|
|
loc, err := time.LoadLocation(location)
|
|
if err != nil {
|
|
return time.Unix(0, 0), err
|
|
}
|
|
switch strings.ToLower(format) {
|
|
case "ansic":
|
|
format = time.ANSIC
|
|
case "unixdate":
|
|
format = time.UnixDate
|
|
case "rubydate":
|
|
format = time.RubyDate
|
|
case "rfc822":
|
|
format = time.RFC822
|
|
case "rfc822z":
|
|
format = time.RFC822Z
|
|
case "rfc850":
|
|
format = time.RFC850
|
|
case "rfc1123":
|
|
format = time.RFC1123
|
|
case "rfc1123z":
|
|
format = time.RFC1123Z
|
|
case "rfc3339":
|
|
format = time.RFC3339
|
|
case "rfc3339nano":
|
|
format = time.RFC3339Nano
|
|
case "stamp":
|
|
format = time.Stamp
|
|
case "stampmilli":
|
|
format = time.StampMilli
|
|
case "stampmicro":
|
|
format = time.StampMicro
|
|
case "stampnano":
|
|
format = time.StampNano
|
|
}
|
|
return time.ParseInLocation(format, ts, loc)
|
|
default:
|
|
return time.Unix(0, 0), errUnsupportedFormat
|
|
}
|
|
}
|