最近在解析 Go
的日期数据格式时(mysql
的 datetime
类型)时遇到个问题,在网上搜了很多方案都试了以后发现不可行,于是自己尝试解决后将解决方案发布出来。
Go
自身的 time.Time
类型默认解析的日期格式是 RFC3339
标准,也就是 2006-01-02T15:04:05Z07:00
的格式。如果我们想要在 Gin
的 shouldBindJSON
方法中,传入 YYYY-MM-DD hh:mm:ss
格式的日期格式作为 time.Time
类型的值,就会引发类似于 parsing time xx as xx: cannot parse xx as xx
的报错信息。这是因为 time.Time
类型默认支持的日期格式与我们传入的格式不同,导致解析出错。。
遇到这个问题后,我在网上找了很多方案,发现都失败了。有的可以完成正常解析,但是无法正确写入到数据库。有的可以正常写入和写出,但是会使得 gin
自带的验证规则如 binding:"required"
规则失效,失去校验的功能。
自定义 LocalTime
类型
解决这个问题的关键就是解决 c.ShouldBindJSON
和 gorm.Updates
的问题,我们需要定义一个新的 Time
类型和自定义的日期格式解析(如下),并将我们的 struct
结构体 datetime
字段指定为我们自定义的类型(如下)
- 自定义
LocalTime
类型
// model.LocalTime
package model
const TimeFormat = "2006-01-02 15:04:05"
type LocalTime time.Time
- 业务代码结构
// You Application Struct
package order
type OrderTest struct {
OrderId int `json:"order_id"`
Test string `json:"test"`
PaymentTime *model.LocalTime `json:"payment_time" binding:"required"`
TestTime *model.LocalTime `json:"test_time"`
}
解析 JSON 格式数据 - UnmarshalJSON
与 MarshalJSON
在 c.ShouldBindJSON
时,会调用 field.UnmarshalJSON
方法,所以我们需要先设置这个方法(如下):
func (t *LocalTime) UnmarshalJSON(data []byte) (err error) {
// 空值不进行解析
if len(data) == 2 {
*t = LocalTime(time.Time{
})
return
}
// 指定解析的格式
now, err := time.Parse(`"`+TimeFormat+`"`, string(data))
*t = LocalTime(now)
return
}
在 UnmarshalJSON
解析后,shouldBindJSON
就可以正常解析 YYYY-MM-DD hh:mm:ss
格式的日期格式了,这样一来就解决了 parsing time xx as xx: cannot parse xx as xx
的问题。
既然解决了 shouldBindJSON
的问题,我们还需要解决 c.JSON
时解析值的问题(实现如下)
func