Skip to content

Commit

Permalink
feat(transformers): convert absolute time to unix nano
Browse files Browse the repository at this point in the history
Signed-off-by: Rodney Osodo <[email protected]>
  • Loading branch information
rodneyosodo committed Mar 14, 2024
1 parent 22a3c29 commit 8f1727f
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 4 deletions.
2 changes: 1 addition & 1 deletion pkg/transformers/json/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func (ts *transformerService) transformTimeField(payload map[string]interface{})
return 0, err
}

return t.UnixNano(), nil
return transformers.ToUnixNano(t.UnixNano()), nil
}
}

Expand Down
12 changes: 10 additions & 2 deletions pkg/transformers/senml/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,16 @@ func (t transformer) Transform(msg *messaging.Message) (interface{}, error) {
// Use reception timestamp if SenML messsage Time is missing
t := v.Time
if t == 0 {
// Convert the Unix timestamp in nanoseconds to float64
t = float64(msg.GetCreated()) / float64(1e9)
t = float64(msg.GetCreated())
}

// If time is below 2**28 it is relative to the current time
// https://datatracker.ietf.org/doc/html/rfc8428#section-4.5.3
if t > 1<<28 {
t = transformers.ToUnixNano(t)
}
if v.UpdateTime > 1<<28 {
v.UpdateTime = transformers.ToUnixNano(v.UpdateTime)
}

msgs[i] = Message{
Expand Down
2 changes: 1 addition & 1 deletion pkg/transformers/senml/transformer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (

func TestTransformJSON(t *testing.T) {
// Following hex-encoded bytes correspond to the content of:
// [{-2: "base-name", -3: 100.0, -4: "base-unit", -1: 10, -5: 10.0, -6: 100.0, 0: "name", 1: "unit", 6: 300.0, 7: 150.0, 2: 42.0, 5: 10.0}]
// [{"bn":"base-name","bt":100,"bu":"base-unit","bver":10,"bv":10,"bs":100,"n":"name","u":"unit","t":300,"ut":150,"v":42,"s":10}]
// For more details for mapping SenML labels to integers, please take a look here: https://tools.ietf.org/html/rfc8428#page-19.
jsonBytes, err := hex.DecodeString("5b7b22626e223a22626173652d6e616d65222c226274223a3130302c226275223a22626173652d756e6974222c2262766572223a31302c226276223a31302c226273223a3130302c226e223a226e616d65222c2275223a22756e6974222c2274223a3330302c227574223a3135302c2276223a34322c2273223a31307d5d")
assert.Nil(t, err, "Decoding JSON expected to succeed")
Expand Down
25 changes: 25 additions & 0 deletions pkg/transformers/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,28 @@ type Transformer interface {
// Transform Magistrala message to any other format.
Transform(msg *messaging.Message) (interface{}, error)
}

type number interface {
uint64 | int64 | float64
}

// ToUnixNano converts time to UnixNano time format.
func ToUnixNano[N number](t N) N {
if t == 0 {
return 0
}
// Check if the value is in nanoseconds
if t > 1e18 {
return t
}
// Check if the value is in milliseconds
if t > 1e15 && t < 1e18 {
return t * 1e3
}
// Check if the value is in microseconds
if t > 1e12 && t < 1e15 {
return t * 1e6
}
// Assume it's in seconds (Unix time)
return t * 1e9
}
110 changes: 110 additions & 0 deletions pkg/transformers/transformer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0

package transformers_test

import (
"testing"
"time"

"github.com/absmach/magistrala/pkg/transformers"
)

var now = time.Now()

func TestInt64ToUnixNano(t *testing.T) {
cases := []struct {
desc string
time int64
want int64
}{
{
desc: "empty",
time: 0,
want: 0,
},
{
desc: "unix",
time: now.Unix(),
want: now.Unix() * int64(time.Second),
},
{
desc: "unix milli",
time: now.UnixMilli(),
want: now.UnixMilli() * int64(time.Millisecond),
},
{
desc: "unix micro",
time: now.UnixMicro(),
want: now.UnixMicro() * int64(time.Microsecond),
},
{
desc: "unix nano",
time: now.UnixNano(),
want: now.UnixNano(),
},
}

for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
got := transformers.ToUnixNano(c.time)
if got != c.want {
t.Errorf("ToUnixNano(%d) = %d; want %d", c.time, got, c.want)
}
t.Logf("ToUnixNano(%d) = %d; want %d", c.time, got, c.want)
})
}
}

func TestFloat64ToUnixNano(t *testing.T) {
cases := []struct {
desc string
time float64
want float64
}{
{
desc: "empty",
time: 0,
want: 0,
},
{
desc: "unix",
time: float64(now.Unix()),
want: float64(now.Unix() * int64(time.Second)),
},
{
desc: "unix milli",
time: float64(now.UnixMilli()),
want: float64(now.UnixMilli() * int64(time.Millisecond)),
},
{
desc: "unix micro",
time: float64(now.UnixMicro()),
want: float64(now.UnixMicro() * int64(time.Microsecond)),
},
{
desc: "unix nano",
time: float64(now.UnixNano()),
want: float64(now.UnixNano()),
},
}

for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
got := transformers.ToUnixNano(c.time)
if got != c.want {
t.Errorf("ToUnixNano(%f) = %f; want %f", c.time, got, c.want)
}
t.Logf("ToUnixNano(%f) = %f; want %f", c.time, got, c.want)
})
}
}

func BenchmarkToUnixNano(b *testing.B) {
for i := 0; i < b.N; i++ {
transformers.ToUnixNano(now.Unix())
transformers.ToUnixNano(now.UnixMilli())
transformers.ToUnixNano(now.UnixMicro())
transformers.ToUnixNano(now.UnixNano())
}
}

0 comments on commit 8f1727f

Please sign in to comment.