自定义时间类型UnmarshalJSON异常:Gin ShouldBindJSON返回非预期值
问题
我定义了如下自定义时间类型及Gin处理器:
type Bday time.Time func (mt *Bday) UnmarshalJSON(bs []byte) (err error) { var t time.Time layout := "2006-01-02T15:04:05Z0700" // RFC3339 s := strings.Trim(string(bs), `"`) t, err = time.Parse(layout, s) if err != nil { return err } *mt = Bday(t) return } func (mt Bday) MarshalJSON() ([]byte, error) { timestamp := time.Time(mt) return json.Marshal(timestamp) } type LoginHandler struct { db *gorm.DB } func (l *LoginHandler) Signup(c *gin.Context) { // Verify name, lastName, email, password, gender, birthDate var user User if err := c.ShouldBindJSON(&user); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), 8) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } user.Password = string(hashedPassword) fmt.Println("User", user) // Save to db l.db.Debug().Model(&models.User{}).Create(&user) // Return code 201 c.JSON(http.StatusCreated, gin.H{"message": "User created successfully!"}) }
User结构体定义如下:
type User struct { Password string `json:"password"` Email string `json:"email"` Name string `json:"name"` LastName string `json:"last_name"` Bday Bday `json:"bday"` Gender string `json:"gender"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt time.Time `json:"deleted_at"` }
在处理器中用fmt.Println打印User时,Bday字段显示为{0 63082400645 <nil>},完整打印内容为:
User {$2a$08$uTE7Llc6YM2owu.D6UWqpOcOVFHRFRrSxbkxWV4ecR72G6kK5/SNq d.n.m@gmail.com Antonio Magalhães {0 63082400645 <nil>} M 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC}
我预期Bday字段应显示类似2001-01-01 00:00:00 +0000 UTC的日期格式,请问这是什么原因?
原因与解决方法
原因
你自定义的Bday是基于time.Time的新类型,但没有实现String()接口。fmt.Println打印结构体时,对于未实现String()的类型,会直接输出其底层结构体的内部字段,也就是time.Time的原始存储结构({wall ext loc}),所以出现了{0 63082400645 <nil>}这种格式。
而原生time.Time本身已经实现了String()接口,所以CreatedAt这类字段能输出格式化后的日期字符串。
解决办法
给Bday类型实现String()方法,直接复用time.Time的格式化逻辑即可:
func (mt Bday) String() string { return time.Time(mt).String() }
这样再用fmt.Println打印User时,Bday字段就会和原生time.Time一样,输出如2001-01-01 00:00:00 +0000 UTC的格式化字符串。
如果需要自定义打印格式,也可以在String()方法里指定布局:
func (mt Bday) String() string { return time.Time(mt).Format("2006-01-02 15:04:05") }
内容的提问来源于stack exchange,提问作者Renato N_
相关产品推荐
相关产品推荐

