登录
首页 >  数据库 >  MySQL

Go 自定义日期时间格式解析解决方案 - 解决 `parsing time xx as xx` 错误

来源:SegmentFault

时间:2023-02-16 15:26:23 489浏览 收藏

本篇文章主要是结合我之前面试的各种经历和实战开发中遇到的问题解决经验整理的,希望这篇《Go 自定义日期时间格式解析解决方案 - 解决 `parsing time xx as xx` 错误》对你有很大帮助!欢迎收藏,分享给更多的需要的朋友学习~

最近在解析

// 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 格式数据 -
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
}

func (t LocalTime) MarshalJSON() ([]byte, error) {
    b := make([]byte, 0, len(TimeFormat)+2)
    b = append(b, '"')
    b = time.Time(t).AppendFormat(b, TimeFormat)
    b = append(b, '"')
    return b, nil
}

数据库写入和写出问题 -
// 写入 mysql 时调用
func (t LocalTime) Value() (driver.Value, error) {
    // 0001-01-01 00:00:00 属于空值,遇到空值解析成 null 即可
    if t.String() == "0001-01-01 00:00:00" {
        return nil, nil
    }
    return []byte(time.Time(t).Format(TimeFormat)), nil
}

// 检出 mysql 时调用
func (t *LocalTime) Scan(v interface{}) error {
    // mysql 内部日期的格式可能是 2006-01-02 15:04:05 +0800 CST 格式,所以检出的时候还需要进行一次格式化
    tTime, _ := time.Parse("2006-01-02 15:04:05 +0800 CST", v.(time.Time).String())
    *t = LocalTime(tTime)
    return nil
}

// 用于 fmt.Println 和后续验证场景
func (t LocalTime) String() string {
    return time.Time(t).Format(TimeFormat)
}

如此一来,我们就可以正常解析存取

package model

import (
    "database/sql/driver"
    "time"
)

const TimeFormat = "2006-01-02 15:04:05"

type LocalTime time.Time

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
}

func (t LocalTime) MarshalJSON() ([]byte, error) {
    b := make([]byte, 0, len(TimeFormat)+2)
    b = append(b, '"')
    b = time.Time(t).AppendFormat(b, TimeFormat)
    b = append(b, '"')
    return b, nil
}

func (t LocalTime) Value() (driver.Value, error) {
    if t.String() == "0001-01-01 00:00:00" {
        return nil, nil
    }
    return []byte(time.Time(t).Format(TimeFormat)), nil
}

func (t *LocalTime) Scan(v interface{}) error {
    tTime, _ := time.Parse("2006-01-02 15:04:05 +0800 CST", v.(time.Time).String())
    *t = LocalTime(tTime)
    return nil
}

func (t LocalTime) String() string {
    return time.Time(t).Format(TimeFormat)
}

解决验证器
package app

func ValidateJSONDateType(field reflect.Value) interface{} {
    if field.Type() == reflect.TypeOf(model.LocalTime{}) {
    timeStr := field.Interface().(model.LocalTime).String()
        // 0001-01-01 00:00:00 是 go 中 time.Time 类型的空值
        // 这里返回 Nil 则会被 validator 判定为空值,而无法通过 `binding:"required"` 规则
        if timeStr == "0001-01-01 00:00:00" {
            return nil
        }
        return timeStr
  }
    return nil
}

func Run() {
    router := gin.Default()

    if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
    // 注册 model.LocalTime 类型的自定义校验规则
        v.RegisterCustomTypeFunc(ValidateJSONDateType, model.LocalTime{})
  }
}

加上这条自定义规则后,我们的校验规则又可以生效了,问题完美解决!(见下图)

图

这个问题困惑了我好几天,一开始想快点解决,在网上找了很多方案拿过来

copy
后,都没有解决问题。最后决定静下来心来,思考其背后的原理,仔细分析,最终靠自己攻克了这个问题,真是不容易。

这件事也让我明白了一个道理,授人予鱼不如授人予渔,所以我在这里也把解决问题的思路分享出来,希望对大家也能有一点理解上的提升。

最后一件事

如果本文对您有帮助的话,请点个赞和收藏吧!

您的点赞是对作者的最大鼓励,也可以让更多人看到本篇文章!

原文地址

理论要掌握,实操不能落!以上关于《Go 自定义日期时间格式解析解决方案 - 解决 `parsing time xx as xx` 错误》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

声明:本文转载于:SegmentFault 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>
评论列表