I am starting A tour of Go, but I am experimenting on the way.
I wrote a piece of code:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
actualTime := time.Now()
fmt.Println(actualTime)
var marshalledtime []byte
marshalledtime,_ := actualTime.MarshalJSON()
fmt.Println(marshalledtime)
actualTime := (*time.Time).UnmarshalJSON(marshalledtime)
fmt.Println(actualTime)
}
I just wanted to marshal a simple date, and then unmarshal it to just see the process.
But I am completely overhelmed with problems. Up to today GO seemed to be so simple and logical, but now... I don't know, I am stuck.
./compile219.go:27:13: cannot use time.(*Time).UnmarshalJSON(marshalledtime) (type error) as type time.Time in assignment
./compile219.go:27:42: not enough arguments in call to method expression time.(*Time).UnmarshalJSON
have ([]byte)
want (*time.Time, []byte)
Why does the last error mean? The documentation clearly says that UnmarshalJson
takes only one argument, byte[]
.
What is with the type conversion error?
The documentation clearly says that UnmarshalJson takes only one argument, byte[]
UnmarshalJson
is the method in case you want to redefine the behavior of Unmarshal
on a struct. That's not the case here. You don't have to use it unless you want to customize Unmarshal
. Then UnmarshalJson will be called under the hood when you will make a call to Unmarshal
By the way, if you see the signature of UnmarshalJson
you will see that it does return only an error.
Here is a fix using json.Unmarshal
package main
import (
"fmt"
"encoding/json"
"time"
)
func main() {
actualTime := time.Now()
fmt.Println(actualTime)
var marshalledtime []byte
marshalledtime,_ = actualTime.MarshalJSON()
fmt.Println(marshalledtime)
json.Unmarshal(marshalledtime, &actualTime)
fmt.Println(actualTime)
}
actualTime.MarshalJSON()
is a method call, it calls the Time.MarshalJSON()
method. It returns you the bytes of the JSON representation of the time. Since the bytes printed are not well readable, you should print the byte slice as a string, e.g.:
fmt.Println("Raw:", marshalledtime)
fmt.Println("String:", string(marshalledtime))
Which outputs:
Raw: [34 50 48 48 57 45 49 49 45 49 48 84 50 51 58 48 48 58 48 48 90 34]
String: "2009-11-10T23:00:00Z"
UnmarshalJSON()
is also a method of time.Time
, so you need a time.Time
value to call it "on", for example:
var time2 time.Time
time2.UnmarshalJSON(marshalledtime)
(To be precise, UnmarshalJSON()
requires a pointer of type *time.Time
because it has to modify the time.Time
value, but the Go compiler will rewrite time2.UnmarshalJSON()
to take time2
's address: (&time2).UnmarshalJSON()
).
MarshalJSON()
and UnmarshalJSON()
also return an error which you should always check, for example:
var marshalledtime []byte
var err error
marshalledtime, err = actualTime.MarshalJSON()
if err != nil {
panic(err)
}
And:
var time2 time.Time
err = time2.UnmarshalJSON(marshalledtime)
if err != nil {
panic(err)
}
Try the fixed code on the Go Playground.
Also note that it's rare that someone calls Time.MarshalJSON()
and Time.UnmarshalJSON()
"by hand". They are to implement the json.Marshaler
and json.Unmarshaler
interfaces, so when you marshal / unmarshal time values, the encoding/json
package will call these methods to do the JSON conversion.
This is how the same can be achieved using the encoding/json
package (try it on the Go Playground):
Marshaling:
var marshalledtime []byte
var err error
marshalledtime, err = json.Marshal(actualTime)
if err != nil {
panic(err)
}
Unmarshaling:
var time2 time.Time
err = json.Unmarshal(marshalledtime, &time2)
if err != nil {
panic(err)
}
Although it's not simpler or shorter in this case, the encoding/json
package is capable of marshaling / unmarshaling arbitrary complex data structures, not just simple time values.