You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义时间类型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_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 21:52:45