当前位置:首页 > 文章列表 > Golang > Go教程 > golang xorm及time.Time自定义解决json日期格式的问题

golang xorm及time.Time自定义解决json日期格式的问题

来源:脚本之家 2022-12-31 21:14:48 0浏览 收藏

IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《golang xorm及time.Time自定义解决json日期格式的问题》,聊聊time、JSON、xorm,我们一起来看看吧!

golang默认的time.Time类型在转为json格式时不是常用的2019-05-08 10:00:01这种格式,解决办法是自定义一个时间类型,例如

type myTime time.Time ,然后针对myTime实现Marshaler接口的MarshalJSON方法,例如:

package models 
import (
 "database/sql/driver"
 "time"
)
 
const localDateTimeFormat string = "2006-01-02 15:04:05" 
type LocalTime time.Time 
func (l LocalTime) MarshalJSON() ([]byte, error) {
 b := make([]byte, 0, len(localDateTimeFormat)+2)
 b = append(b, '"')
 b = time.Time(l).AppendFormat(b, localDateTimeFormat)
 b = append(b, '"')
 return b, nil
}
 
func (l *LocalTime) UnmarshalJSON(b []byte) error {
 now, err := time.ParseInLocation(`"`+localDateTimeFormat+`"`, string(b), time.Local)
 *l = LocalTime(now)
 return err
}

上面的代码在网上随手一搜就能找到,没有什么困难的,接下来的才是本篇文章的重点,这玩意结合xorm使用时,特别是字段类型为*LocalTime的时候才需要折腾一番。

下面是我的对应数据库表结构的struct 定义,

type ServerInfo struct {
 ServerInfoId       string   `xorm:"varchar(32) pk server_info_id"`
 CreatedAt        LocalTime `xorm:"timestamp created"`
 UpdatedAt        LocalTime `xorm:"timestamp updated"`
 DeletedAt        *LocalTime `xorm:"timestamp deleted index"`
 OrgId          string   `xorm:"varchar(100) org_id" json:"orgId"`                        
 ServerIp         string   `xorm:"varchar(128) server_ip" json:"serverIp"`                     
 ServerNameDesc      string   `xorm:"varchar(500) server_name_desc" json:"serverNameDesc"`               
 ServerTimeNow      LocalTime `xorm:"timestamp server_time" json:"serverTime"`                     
 DataReceiveTime     LocalTime `xorm:"timestamp data_receive_time" sql:"DEFAULT:current_timestamp" json:"dataRecvTime"` 
 LastUploadDataTime    *LocalTime `xorm:"timestamp last_upload_data_time" json:"lastUploadDataTime"`            
 LastCheckTime      *LocalTime `xorm:"timestamp last_check_time" json:"lastCheckTime"`                 
 LastErrorTime      *LocalTime `xorm:"timestamp last_error_time" json:"lastErrorTime"`                 
}

注意上面的字段类型,既有LocalTime类型的,又有*LocalTime类型的,*LocalTime是考虑到有时候数据值可能为NULL,即字段值可能为空的情况。

xorm不知道如何为LocalTime这个自定义类型进行赋值或者取值,因此需要实现xorm的core包中的Conversion接口,这个接口的定义如下:

注意,坑已经隐藏在上面的接口定义中了,过一会说。

整个完整的自定义时间类型的代码变成了下面的这样:

package models 
import (
 "database/sql/driver"
 "time"
)
 
const localDateTimeFormat string = "2006-01-02 15:04:05" 
type LocalTime time.Time 
func (l LocalTime) MarshalJSON() ([]byte, error) {
 b := make([]byte, 0, len(localDateTimeFormat)+2)
 b = append(b, '"')
 b = time.Time(l).AppendFormat(b, localDateTimeFormat)
 b = append(b, '"')
 return b, nil
}
 
func (l *LocalTime) UnmarshalJSON(b []byte) error {
 now, err := time.ParseInLocation(`"`+localDateTimeFormat+`"`, string(b), time.Local)
 *l = LocalTime(now)
 return err
}
 
func (l LocalTime) String() string {
 return time.Time(l).Format(localDateTimeFormat)
}
 
func (l LocalTime)Now()(LocalTime){
 return LocalTime(time.Now())
}
 
func (l LocalTime)ParseTime(t time.Time)(LocalTime){
 return LocalTime(t)
}
 
func (j LocalTime) format() string {
 return time.Time(j).Format(localDateTimeFormat)
}
 
func (j LocalTime) MarshalText() ([]byte, error) {
 return []byte(j.format()), nil
}
 
func (l *LocalTime) FromDB(b []byte) error {
 if nil == b || len(b) == 0 {
 l = nil
 return nil
 }
 var now time.Time
 var err error
 now, err = time.ParseInLocation(localDateTimeFormat, string(b), time.Local)
 if nil == err {
 *l = LocalTime(now)
 return nil
 }
 now, err = time.ParseInLocation("2006-01-02T15:04:05Z", string(b), time.Local)
 if nil == err {
 *l = LocalTime(now)
 return nil
 }
 panic("自己定义个layout日期格式处理一下数据库里面的日期型数据解析!")
 return err
}
 
//func (t *LocalTime) Scan(v interface{}) error {
// // Should be more strictly to check this type.
// vt, err := time.Parse("2006-01-02 15:04:05", string(v.([]byte)))
// if err != nil {
// return err
// }
// *t = LocalTime(vt)
// return nil
//}
 
func (l *LocalTime) ToDB() ([]byte, error) {
 if nil == l {
 return nil,nil
 }
 return []byte(time.Time(*l).Format(localDateTimeFormat)), nil
}
 
func (l *LocalTime) Value() (driver.Value, error) {
 if nil==l {
 return nil, nil
 }
 return time.Time(*l).Format(localDateTimeFormat), nil
}

此时,要是数据库的字段内容都有值的话插入和更新应该是没有什么问题,但是*LocalTime字段的值为nil的话问题就开始出现了,上面说了,ToDB()方法的返回值类型为[]byte,当字段值为nil时,返回nil看上去一切正常,但是xorm打印出来的sql语句数据值是下面这个样子的:

这个[]uint8(nil)就是*LocalTime值为nil时的情况,数据库驱动是不认可[]uint8(nil)这种数据去写给timestamp类型字段的,问题的根源就是ToDB方法的返回值类型为[]byte,既然是这样,就需要我们人为的把[]uint8(nil)这种类型改为interface(nil)类型,数据库驱动会识别interface(nil)为NULL值,修改代码xorm\statement.go第322行,把原来的val=data改成下面的样子:

就是把val=data改为 if nil==data { val=nil } else {val=data} ,看上去逻辑没有什么变化,但是给val=nil赋值的时候,val的类型就从[]uint8(nil)变成了interface(nil)了,这样数据库驱动就可以正确处理空值了。

除了需要修改xorm\statement.go文件的内容,还需要修改xorm\session_convert.go的第558行,增加以下代码:

主要是增加下面的代码

//fix when pointer type value is null,added by peihexian,2019-05-07
if nil==data {
  return nil,nil
}

之所以加这个代码是因为xorm作者没有考虑指针类型字段值为nil的情况,xorm对有转换的字段要么当成数字,要么当成了字符串,这两种对于NULL类型的值都不适用,所以需要增加if nil==data return nil,nil这样的代码,还是把数据值组织成interface(nil)去给数据库驱动去处理。

另外还有一个地方,是session_convert.go 第556行,同样需要增加

if nil==data { //edit by peihexian 2019.06.19
  return nil,nil
}

下面是加完以后的样子

到这里,对xorm做了几处小的修改,自定义日期的问题及json格式化问题完美解决。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持golang学习网。如有错误或未考虑完全的地方,望不吝赐教。

今天带大家了解了time、JSON、xorm的相关知识,希望对你有所帮助;关于Golang的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

版本声明
本文转载于:脚本之家 如有侵犯,请联系study_golang@163.com删除
golang time包做时间转换操作golang time包做时间转换操作
上一篇
golang time包做时间转换操作
golang xorm日志写入文件中的操作
下一篇
golang xorm日志写入文件中的操作
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    514次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    499次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • SEO  AI Mermaid 流程图:自然语言生成,文本驱动可视化创作
    AI Mermaid流程图
    SEO AI Mermaid 流程图工具:基于 Mermaid 语法,AI 辅助,自然语言生成流程图,提升可视化创作效率,适用于开发者、产品经理、教育工作者。
    619次使用
  • 搜获客笔记生成器:小红书医美爆款内容AI创作神器
    搜获客【笔记生成器】
    搜获客笔记生成器,国内首个聚焦小红书医美垂类的AI文案工具。1500万爆款文案库,行业专属算法,助您高效创作合规、引流的医美笔记,提升运营效率,引爆小红书流量!
    625次使用
  • iTerms:一站式法律AI工作台,智能合同审查起草与法律问答专家
    iTerms
    iTerms是一款专业的一站式法律AI工作台,提供AI合同审查、AI合同起草及AI法律问答服务。通过智能问答、深度思考与联网检索,助您高效检索法律法规与司法判例,告别传统模板,实现合同一键起草与在线编辑,大幅提升法律事务处理效率。
    643次使用
  • TokenPony:AI大模型API聚合平台,一站式接入,高效稳定高性价比
    TokenPony
    TokenPony是讯盟科技旗下的AI大模型聚合API平台。通过统一接口接入DeepSeek、Kimi、Qwen等主流模型,支持1024K超长上下文,实现零配置、免部署、极速响应与高性价比的AI应用开发,助力专业用户轻松构建智能服务。
    709次使用
  • 迅捷AIPPT:AI智能PPT生成器,高效制作专业演示文稿
    迅捷AIPPT
    迅捷AIPPT是一款高效AI智能PPT生成软件,一键智能生成精美演示文稿。内置海量专业模板、多样风格,支持自定义大纲,助您轻松制作高质量PPT,大幅节省时间。
    606次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码