| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- package ionet
- import (
- "encoding/json"
- "strings"
- "time"
- "github.com/samber/lo"
- )
- // decodeWithFlexibleTimes unmarshals API responses while tolerating timestamp strings
- // that omit timezone information by normalizing them to RFC3339Nano.
- func decodeWithFlexibleTimes(data []byte, target interface{}) error {
- var intermediate interface{}
- if err := json.Unmarshal(data, &intermediate); err != nil {
- return err
- }
- normalized := normalizeTimeValues(intermediate)
- reencoded, err := json.Marshal(normalized)
- if err != nil {
- return err
- }
- return json.Unmarshal(reencoded, target)
- }
- func decodeData[T any](data []byte, target *T) error {
- var wrapper struct {
- Data T `json:"data"`
- }
- if err := json.Unmarshal(data, &wrapper); err != nil {
- return err
- }
- *target = wrapper.Data
- return nil
- }
- func decodeDataWithFlexibleTimes[T any](data []byte, target *T) error {
- var wrapper struct {
- Data T `json:"data"`
- }
- if err := decodeWithFlexibleTimes(data, &wrapper); err != nil {
- return err
- }
- *target = wrapper.Data
- return nil
- }
- func normalizeTimeValues(value interface{}) interface{} {
- switch v := value.(type) {
- case map[string]interface{}:
- return lo.MapValues(v, func(val interface{}, _ string) interface{} {
- return normalizeTimeValues(val)
- })
- case []interface{}:
- return lo.Map(v, func(item interface{}, _ int) interface{} {
- return normalizeTimeValues(item)
- })
- case string:
- if normalized, changed := normalizeTimeString(v); changed {
- return normalized
- }
- return v
- default:
- return value
- }
- }
- func normalizeTimeString(input string) (string, bool) {
- trimmed := strings.TrimSpace(input)
- if trimmed == "" {
- return input, false
- }
- if _, err := time.Parse(time.RFC3339Nano, trimmed); err == nil {
- return trimmed, trimmed != input
- }
- if _, err := time.Parse(time.RFC3339, trimmed); err == nil {
- return trimmed, trimmed != input
- }
- layouts := []string{
- "2006-01-02T15:04:05.999999999",
- "2006-01-02T15:04:05.999999",
- "2006-01-02T15:04:05",
- }
- for _, layout := range layouts {
- if parsed, err := time.Parse(layout, trimmed); err == nil {
- return parsed.UTC().Format(time.RFC3339Nano), true
- }
- }
- return input, false
- }
|