英文:
Json Decode cannot parse timestamp in json into Go struct
问题
我正在尝试获取一个HTTP请求体,它是一个JSON对象,并将其解码为我定义的Go结构体。
结构体中有两个字段的类型是time.Time
。当只有一个这样类型的字段时,一切正常。
但是,如果在Go结构体中有多个time.Time
类型的字段,我无法解码它,并得到以下错误:
2014/11/01 01:07:04 parsing time "null" as ""2006-01-02T15:04:05Z07:00"": cannot parse "null" as """"
问题出在解码的代码行上。尽管我进行了调试,但没有得到有意义的结果。这个问题看起来很奇怪,实际上不应该出现。
我在这里漏掉了什么?
func register(w http.ResponseWriter, r *http.Request){
//读取请求体JSON并转换为Go类型
var requestBody = []byte(`{"username":"qwewwwqweqwe","password":"can","usertype":"student","firstname":"","midname":null,"surname":null,"signuptimestamp":null,"userstatus":null,"phone":null,"email":null,"address":null,"city":null,"country":null,"language":null,"lastlogintimestamp":null}`)
type RegisterStructure struct {
Id int `json:"id"`
Timestamp time.Time `json:"timestamp,omitempty"`
SignupTimestamp time.Time `json:"signuptimestamp,omitempty"`
Username string `json:"username"`
Password string `json:"password"`
UserType string `json:"usertype"`
FirstName string `json:"firstname"`
Midname string `json:"midname"`
Surname string `json:"surname"`
UserStatus string `json:"userstatus"`
Phone string `json:"phone"`
Email string `json:"email"`
Address string `json:"address"`
City string `json:"city"`
Country string `json:"country"`
Language string `json:"language"`
//LastLoginTimestamp time.Time `json:"lastlogintimestamp,omitempty"`
}
var registerInstance RegisterStructure
var now = time.Now()
fmt.Printf("现在是 %v", now)
fmt.Println()
fmt.Printf("1 在这里初始化后的 registerInstance 是 %v", registerInstance)
fmt.Println()
registerInstance = RegisterStructure{Timestamp: now, SignupTimestamp: now}
fmt.Printf("在这里将其设置为变量 now 后的 registerInstance 是 %v", registerInstance)
fmt.Println()
dec := json.NewDecoder(bytes.NewReader(requestBody))
err = dec.Decode(®isterInstance)
if err != nil {
fmt.Printf("这里发生了错误。")
log.Fatal(err)
}
}
英文:
I am trying to obtain an HTTP request body which is a json object and decode it into a Go struct I have defined.
Two of the fields of the struct is of time.Time
type. While having only one such typed field everything works correctly.
If I have more than one time.Time
typed fields in the go struct I cannot decode it and get the error:
2014/11/01 01:07:04 parsing time "null" as ""2006-01-02T15:04:05Z07:00"": cannot parse "null" as """
The problem is in the decoding lines. Despite my debugging efforts I could have reached a meaningful result. That issue seems strange which is actually should not be.
What am I missing here?
func register(w http.ResponseWriter, r *http.Request){
//Read Request Body JSON Into Go Types
var requestBody = []byte(`{"username":"qwewwwqweqwe","password":"can","usertype":"student","firstname":"","midname":null,"surname":null,"signuptimestamp":null,"userstatus":null,"phone":null,"email":null,"address":null,"city":null,"country":null,"language":null,"lastlogintimestamp":null}`)
type RegisterStructure struct {
Id int `json:"id"`
Timestamp time.Time `json:"timestamp,omitemty"`
SignupTimestamp time.Time `json:"signuptimestamp,omitempty"`
Username string `json:"username"`
Password string `json:"password"`
UserType string `json:"usertype"`
FirstName string `json:"firstname"`
Midname string `json:"midname"`
Surname string `json:"surname"`
UserStatus string `json:"userstatus"`
Phone string `json:"phone"`
Email string `json:"email"`
Address string `json:"address"`
City string `json:"city"`
Country string `json:"country"`
Language string `json:"language"`
//LastLoginTimestamp time.Time `json:"lastlogintimestamp,omitempty"`
}
var registerInstance RegisterStructure
var now = time.Now()
fmt.Printf("now is %v", now)
fmt.Println()
fmt.Printf("1 registerInstance after inited here is %v", registerInstance)
fmt.Println()
registerInstance = RegisterStructure{Timestamp: now, SignupTimestamp: now,}
fmt.Printf("registerInstance after set to var now here is %v", registerInstance)
fmt.Println()
dec := json.NewDecoder(bytes.NewReader(requestBody))
err = dec.Decode(&registerInstance)
if err != nil {
fmt.Printf("error happens here.")
log.Fatal(err)
}
答案1
得分: 7
好的,下面是翻译好的内容:
好的。这是一个可复现的示例,演示了你所看到的错误。
package main
import (
"encoding/json"
"fmt"
"bytes"
"time"
)
type RegisterStructure struct {
SignupTimestamp time.Time `json:"signuptimestamp,omitempty"`
}
func main() {
requestBody := []byte(`{"signuptimestamp" : null}`)
dec := json.NewDecoder(bytes.NewReader(requestBody))
registerInstance := RegisterStructure{}
err := dec.Decode(®isterInstance)
if err != nil {
fmt.Println(err)
}
}
你所看到的错误与有多个时间戳无关。这就是为什么在调试这种情况时,展示输入是至关重要的,你应该返回并更改你的问题,将一个示例的requestBody
作为问题内容的一部分。否则,很难猜测你在做什么。
问题出在null
值没有被time.Time
的JSON解码器处理。time.Time
的文档中写道:UnmarshalJSON实现了json.Unmarshaler接口。时间应该是一个以RFC 3339格式引用的字符串。
null
不是这样的值:在这种情况下,解码器不会尝试为时间戳构造一个“零”值。
你需要做的是将SignupTimestamp
的类型从time.Time
更改为*time.Time
,这样null
值可以明确地表示为nil
指针。
这里有一个示例来演示:
package main
import (
"bytes"
"encoding/json"
"fmt"
"time"
)
type RegisterStructure struct {
SignupTimestamp *time.Time `json:"signuptimestamp,omitempty"`
}
func main() {
requestBodies := []string{
`{"signuptimestamp" : "1985-04-12T23:20:50.52Z"}`,
`{"signuptimestamp" : null}`,
}
for _, requestBody := range requestBodies {
dec := json.NewDecoder(bytes.NewReader([]byte(requestBody)))
registerInstance := RegisterStructure{}
err := dec.Decode(®isterInstance)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%#v\n", registerInstance)
}
}
英文:
Ok. Here is a reproducible example that demonstrates the error you're seeing.
package main
import (
"encoding/json"
"fmt"
"bytes"
"time"
)
type RegisterStructure struct {
SignupTimestamp time.Time `json:"signuptimestamp,omitempty"`
}
func main() {
requestBody := []byte(`{"signuptimestamp" : null}`)
dec := json.NewDecoder(bytes.NewReader(requestBody))
registerInstance := RegisterStructure{}
err := dec.Decode(&registerInstance)
if err != nil {
fmt.Println(err)
}
}
The error you're seeing has nothing to do with having multiple timestamps. This is why showing inputs is critical for debugging situations like this, and why you should go back and change your question to include a sample requestBody
as part of the question content. Otherwise, it becomes very difficult to guess what you're doing.
What's happening is that null
is not handled by the JSON unmarshaller for time.Time
. The documentation for time.Time's unmarshaller says: UnmarshalJSON implements the json.Unmarshaler interface. The time is expected to be a quoted string in RFC 3339 format.
null
is not such a value: the decoder in this case will not try to construct a "zero" value for the timestamp.
What you want to do is change the type of SignupTimestamp
from time.Time
to *time.Time
, so that the null
value can be explicitly represented as a nil
pointer.
Here is an example to demonstrate:
package main
import (
"bytes"
"encoding/json"
"fmt"
"time"
)
type RegisterStructure struct {
SignupTimestamp *time.Time `json:"signuptimestamp,omitempty"`
}
func main() {
requestBodies := []string{
`{"signuptimestamp" : "1985-04-12T23:20:50.52Z"}`,
`{"signuptimestamp" : null}`,
}
for _, requestBody := range requestBodies {
dec := json.NewDecoder(bytes.NewReader([]byte(requestBody)))
registerInstance := RegisterStructure{}
err := dec.Decode(&registerInstance)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%#v\n", registerInstance)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论