mitchellh / mapstructure

Go library for decoding generic map values into native Go structures and vice versa.
https://gist.github.com/mitchellh/90029601268e59a29e64e55bab1c5bdc
MIT License
7.93k stars 677 forks source link

type time.Time Decode Error #301

Closed jwrookie closed 2 years ago

jwrookie commented 2 years ago
package main

import (
    "fmt"
    "github.com/mitchellh/mapstructure"
    "time"
)

type A struct {
    T     time.Time
    Other string
}

type B struct {
    T     time.Time
    Other string
}

func main() {
    a := A{T: time.Now(), Other: "aaa"}
    fmt.Printf("%#v\n", a)

    var b B
    mapstructure.Decode(a, &b)
    fmt.Printf("%#v\n", b)
}

output:
main.A{T:time.Date(2022, time.August, 17, 12, 14, 56, 740104000, time.Local), Other:"aaa"}
main.B{T:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Other:"aaa"}

want:
main.A{T:time.Date(2022, time.August, 17, 12, 14, 56, 740104000, time.Local), Other:"aaa"}
main.B{T:time.Date(2022, time.August, 17, 12, 14, 56, 740104000, time.Local), Other:"aaa"}
jwrookie commented 2 years ago

Because the fields in Time are not exported, which causes the above problem, I can use the following way to solve it

It's not a good code, it just solves the problem

package main

import (
    "fmt"
    "github.com/mitchellh/mapstructure"
    "reflect"
    "time"
)

type A struct {
    T     time.Time
    Other string
}

type B struct {
    T     time.Time
    Other string
}

func main() {
    a := A{T: time.Now(), Other: "xxx"}
    fmt.Printf("%#v\n", a)

    var b B
    MyDecode(a, &b)
    fmt.Printf("%#v\n", b)
}

func ToTimeHookFunc() mapstructure.DecodeHookFunc {
    var value interface{}
    return func(from reflect.Value, to reflect.Value) (interface{}, error) {
        if from.Type() == reflect.TypeOf(&time.Time{}) {
            value = from.Interface()
        }

        if to.Type() == reflect.TypeOf(time.Time{}) {
            return value, nil
        }

        return from.Interface(), nil
    }
}

func MyDecode(input, output interface{}) {
    decoder, _ := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
        Metadata:   nil,
        DecodeHook: ToTimeHookFunc(),
        Result:     output,
    })

    err := decoder.Decode(input)
    if err != nil {
        panic(err)
    }
}