Files
gocryptotrader/types/time.go
Adrian Gallagher 3cc9a2b9e0 exchanges: Refactor time handling and other minor improvements (#1948)
* exchanges: Refactor time handling and other minor improvements

- Updated Kraken wrapper to utilise new time handling methods.
- Simplified Kucoin types by removing unnecessary structures and using direct JSON unmarshalling.
- Improved websocket handling in Kucoin to directly parse candlestick data.
- Modified Lbank types to use the new time representation.
- Adjusted Poloniex wrapper and types to utilise the new time handling.
- Updated Yobit types and wrapper to reflect changes in time representation.
- Introduced DateTime type for better handling of specific time formats.
- Added tests for DateTime unmarshalling to ensure correctness.
- Rid UTC().Unix and UTC().UnixMilli as it's not needed
- Correct Huobi timestamp usage for some endpoints.
- Rid RFC3339 time parsing since Go does that automatically.

* exchanges: Refactor JSON unmarshalling for various types and improve test coverage

* linter: Update error message in TestGetKlines

* refactor: Simplify JSON unmarshalling in MovementHistory and improve test assertions in GetKlines

* refactor: Improve JSON unmarshalling for channel name and clarify comment in wsProcessOpenOrders

* refactor: Update time handling in Huobi types to use types.Time for createdAt fields and relax GetLiquidationOrders test

* refactor: Move wsTicker, wsSpread, wsTrades, and wsCandle types to kraken_types.go for better organistion

* refactor: Add validation for underlying parameter in GetExpirationTime and update tests
2025-07-01 09:11:55 +10:00

105 lines
2.5 KiB
Go

package types
import (
"errors"
"fmt"
"strconv"
"strings"
"time"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
)
// Time represents a time.Time object that can be unmarshalled from a float64 or string.
// MarshalJSON serializes the time to JSON using RFC 3339 format.
// Note: Not all exchanges may support RFC 3339 for outbound requests, so ensure compatibility with each exchange's time
// format requirements.
type Time time.Time
var errInvalidTimestampFormat = errors.New("invalid timestamp format")
// UnmarshalJSON deserializes json, and timestamp information.
func (t *Time) UnmarshalJSON(data []byte) error {
s := string(data)
if s[0] == '"' {
s = s[1 : len(s)-1]
}
if s == "" || s[0] == 'n' || s == "0" {
return nil
}
if target := strings.Index(s, "."); target != -1 {
s = s[:target] + s[target+1:]
if strings.Trim(s, "0") == "" {
return nil
}
}
// Expects a string of length 10 (seconds), 13 (milliseconds), 16 (microseconds), or 19 (nanoseconds) representing a Unix timestamp
switch len(s) {
case 12, 15, 18:
s += "0"
case 11, 14, 17:
s += "00"
}
unixTS, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return fmt.Errorf("error parsing unix timestamp: %w", err)
}
switch len(s) {
case 10:
*t = Time(time.Unix(unixTS, 0))
case 13:
*t = Time(time.UnixMilli(unixTS))
case 16:
*t = Time(time.UnixMicro(unixTS))
case 19:
*t = Time(time.Unix(0, unixTS))
default:
return fmt.Errorf("%w: %q", errInvalidTimestampFormat, data)
}
return nil
}
// Time represents a time instance.
func (t Time) Time() time.Time { return time.Time(t) }
// String returns a string representation of the time.
func (t Time) String() string {
return t.Time().String()
}
// MarshalJSON serializes the time to json.
func (t Time) MarshalJSON() ([]byte, error) {
return t.Time().MarshalJSON()
}
// DateTime represents a time.Time object that can be unmarshalled from a string in the format "2006-01-02 15:04:05".
type DateTime time.Time
// UnmarshalJSON unmarshals json data into a DateTime type.
func (d *DateTime) UnmarshalJSON(data []byte) error {
var ts string
if err := json.Unmarshal(data, &ts); err != nil {
return fmt.Errorf("error unmarshalling %q into string: %w", data, err)
}
tm, err := time.Parse(time.DateTime, ts)
if err != nil {
return fmt.Errorf("error parsing %q into DateTime: %w", ts, err)
}
*d = DateTime(tm)
return nil
}
// Time converts DateTime to time.Time
func (d DateTime) Time() time.Time {
return time.Time(d)
}