I am trying to unmarshal some json into a struct and have the following:
package main
import (
"encoding/json"
"fmt"
"strings"
"time"
)
type Added struct {
Added *time.Time `json:"added"`
}
func main() {
st := strings.NewReader(`{"added": ""}`)
a := &Added{}
err := json.NewDecoder(st).Decode(&a)
if err != nil {
panic(err)
}
fmt.Println(a)
}
Running the above results in:
panic: parsing time """" as ""2006-01-02T15:04:05Z07:00"": cannot parse """ as "2006"
Ok, so I try a custom marshaller:
package main
import (
"encoding/json"
"fmt"
"strings"
"time"
)
type Added struct {
Added *MyTime `json:"added"`
}
func main() {
st := strings.NewReader(`{"added": ""}`)
a := &Added{}
err := json.NewDecoder(st).Decode(&a)
if err != nil {
panic(err)
}
fmt.Println(a)
}
type MyTime struct {
*time.Time
}
func (m *MyTime) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package.
if string(data) == "null" || string(data) == `""` {
return nil
}
// Fractional seconds are handled implicitly by Parse.
tt, err := time.Parse(`"`+time.RFC3339+`"`, string(data))
*m = MyTime{&tt}
return err
}
I then get:
&{%!v(PANIC=runtime error: invalid memory address or nil pointer dereference)}
Ok, now what do I do? I'd simply like to handle the "" value from the json.
My playground with the complete example is found.
Package time
import "time"
type Time
A Time represents an instant in time with nanosecond precision.
Programs using times should typically store and pass them as values, not pointers. That is, time variables and struct fields should be of type time.Time, not *time.Time.
I just kept fixing likely problems, for example, time.Time
, not *time.Time
, a real date, and so on, until I got a reasonable result:
package main
import (
"encoding/json"
"fmt"
"strings"
"time"
)
type MyTime struct {
time.Time
}
func (m *MyTime) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package.
if string(data) == "null" || string(data) == `""` {
return nil
}
// Fractional seconds are handled implicitly by Parse.
tt, err := time.Parse(`"`+time.RFC3339+`"`, string(data))
*m = MyTime{tt}
return err
}
type Added struct {
Added MyTime `json:"added"`
}
func main() {
st := strings.NewReader(`{"added": "2012-04-23T18:25:43.511Z"}`)
var a Added
err := json.NewDecoder(st).Decode(&a)
if err != nil {
panic(err)
}
fmt.Println(a)
}
Playground: https://play.golang.org/p/Uusdp3DkXDU
Output:
{2012-04-23 18:25:43.511 +0000 UTC}
With an empty (""
) date string, the time.Time
zero value, 0001-01-01 00:00:00 +0000 UTC
:
Playground: https://play.golang.org/p/eQoEyqBlhg2
Output:
{0001-01-01 00:00:00 +0000 UTC}
Use the time
IsZero
method to test for the zero value.
func (Time) IsZero
func (t Time) IsZero() bool
IsZero reports whether t represents the zero time instant, January 1, year 1, 00:00:00 UTC.
I think you were very close to the solution with your custom marshaller. Maybe just revert to normal decoding for normal dates. This may help:
type MyTime time.Time
func (m *MyTime) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package.
if string(data) == "null" || string(data) == `""` {
return nil
}
return json.Unmarshal(data, (*time.Time)(m))
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With