types: Add Time type from Gateio and share across codebase (#1648)

* consolidate type to types package and share across code base

* rm convert type and convert codebase

* rm irrelavant test cases

* Fix tests

* glorious nits

* Update exchanges/gateio/gateio_types.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

* thrasher: nits

---------

Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
This commit is contained in:
Ryan O'Hara-Reid
2024-10-01 10:46:55 +10:00
committed by GitHub
parent bfd499f0c9
commit d31fa3ff3d
29 changed files with 2633 additions and 2894 deletions

View File

@@ -1,7 +1,6 @@
package convert
import (
"encoding/json"
"fmt"
"math"
"strconv"
@@ -187,56 +186,3 @@ func InterfaceToStringOrZeroValue(r interface{}) string {
}
return ""
}
// ExchangeTime provides timestamp to time conversion method.
type ExchangeTime time.Time
// UnmarshalJSON is custom type json unmarshaller for ExchangeTime
func (k *ExchangeTime) UnmarshalJSON(data []byte) error {
var timestamp interface{}
err := json.Unmarshal(data, &timestamp)
if err != nil {
return err
}
var standard int64
switch value := timestamp.(type) {
case string:
if value == "" {
// Setting the time to zero value because some timestamp fields could return an empty string while there is no error
// So, in such cases, Time returns zero timestamp.
break
}
standard, err = strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
case int64:
standard = value
case float64:
// Warning: converting float64 to int64 instance may create loss of precision in the timestamp information.
// be aware or consider customizing this section if found necessary.
standard = int64(value)
case nil:
// for some exchange timestamp fields, if the timestamp information is not specified,
// the data is 'nil' instead of zero value string or integer value.
default:
return fmt.Errorf("unsupported timestamp type %T", timestamp)
}
switch {
case standard == 0:
*k = ExchangeTime(time.Time{})
case standard >= 1e13:
*k = ExchangeTime(time.Unix(standard/1e9, standard%1e9))
case standard > 9999999999:
*k = ExchangeTime(time.UnixMilli(standard))
default:
*k = ExchangeTime(time.Unix(standard, 0))
}
return nil
}
// Time returns a time.Time instance from ExchangeTime instance object.
func (k ExchangeTime) Time() time.Time {
return time.Time(k)
}

View File

@@ -1,7 +1,6 @@
package convert
import (
"encoding/json"
"strings"
"testing"
"time"
@@ -316,86 +315,3 @@ func TestInterfaceToStringOrZeroValue(t *testing.T) {
t.Errorf("expected meow, got: %v", x)
}
}
func TestExchangeTimeUnmarshalJSON(t *testing.T) {
t.Parallel()
unmarshaledResult := &struct {
Timestamp ExchangeTime `json:"ts"`
}{}
data1 := `{"ts":""}`
result := time.Time{}
err := json.Unmarshal([]byte(data1), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data2 := `{"ts":"1685564775371"}`
result = time.UnixMilli(1685564775371)
err = json.Unmarshal([]byte(data2), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data3 := `{"ts":1685564775371}`
err = json.Unmarshal([]byte(data3), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data4 := `{"ts":"1685564775"}`
result = time.Unix(1685564775, 0)
err = json.Unmarshal([]byte(data4), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data5 := `{"ts":1685564775}`
err = json.Unmarshal([]byte(data5), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data6 := `{"ts":"1685564775371320000"}`
result = time.Unix(int64(1685564775371320000)/1e9, int64(1685564775371320000)%1e9)
err = json.Unmarshal([]byte(data6), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data7 := `{"ts":"abcdefg"}`
err = json.Unmarshal([]byte(data7), &unmarshaledResult)
if err == nil {
t.Fatal("expecting error but found nil")
}
data8 := `{"ts":0}`
result = time.Time{}
err = json.Unmarshal([]byte(data8), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
}
// 2239239 516.1 ns/op 424 B/op 9 allocs/op
func BenchmarkExchangeTimeUnmarshaling(b *testing.B) {
unmarshaledResult := &struct {
Timestamp ExchangeTime `json:"ts"`
}{}
data5 := `{"ts":1685564775}`
result := time.Unix(1685564775, 0)
var err error
for i := 0; i < b.N; i++ {
if err = json.Unmarshal([]byte(data5), &unmarshaledResult); err != nil {
b.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
b.Fatalf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
}
}