gorm中created_at 时间,go time时间,mysql数据库时间的一些问题总结

gorm中created_at 时间,go time时间,mysql数据库时间的一些问题总结

问题1 gorm中created_at 时间

在生成的时候发现数据库的时间慢了8个小时,后来发现是需要在连接数据库的时候加上参数&loc=local

func init(){
	driverName := viper.GetString("datasource.driverName")
	host := viper.GetString("datasource.host")
	port := viper.GetString("datasource.port")
	database := viper.GetString("datasource.database")
	username := viper.GetString("datasource.username")
	password := viper.GetString("datasource.password")
	charset := viper.GetString("datasource.charset")
	args := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True&loc=Local", //loc=local不能忘记
		username,
		password,
		host,
		port,
		database,
		charset)
	db, err := gorm.Open(driverName, args)
	if err != nil {
		panic("failed to connect database err: " + err.Error())
	}
	db.AutoMigrate(&defs.Users{})
	db.AutoMigrate(&defs.Video_Info{})
	db.AutoMigrate(&defs.Comments{})
	db.AutoMigrate(&defs.Sessions{})
	dbConn=db
}

问题2 go内置的time一些问题

使用time.Parse()解析字符串生成的时间的时区是UTC,而你调用time.Now() 则是CST,这导致你数据库中查时间段的数据会出错,如下代码

func TestListComments(t *testing.T)  {
	vid:="123"
	layout:="Jan 02 2006, 15:04:05"
	from,_:=time.Parse(layout,"Dec 14 2021, 20:18:15")//不加载时区
	fromUnix:=from.Unix()
	fmt.Println(from)
	fmt.Println(fromUnix)
	to:=time.Now()
	toUnix:=to.Unix()
	fmt.Println(to)
	fmt.Println(toUnix)
	comments, err := ListComments(vid, fromUnix, toUnix)
	if err!=nil{
		t.Errorf("Error of list comments:%v",err)
	}
	for _,val:=range comments{
		fmt.Printf("%#v",val)
	}
}

输出有误

2021-12-14 20:18:15 +0000 UTC
1639513095  //开始时间反而大于 结束时间,因为时区不对
2021-12-14 21:22:25.3100649 +0800 CST m=+0.032457601
1639488145

解析字符串并加载时区之后,时区一致

func TestListComments(t *testing.T)  {
	vid:="123"
	layout:="Jan 02 2006, 15:04:05"
	// 加载时区
	loc, err := time.LoadLocation("Asia/Shanghai") //一定要这个否则会弄错的
	from,_:=time.ParseInLocation(layout,"Dec 14 2021, 20:18:15",loc)
	fromUnix:=from.Unix()
	fmt.Println(from)
	fmt.Println(fromUnix)
	to:=time.Now()
	toUnix:=to.Unix()
	fmt.Println(to)
	fmt.Println(toUnix)
	comments, err := ListComments(vid, fromUnix, toUnix)
	if err!=nil{
		t.Errorf("Error of list comments:%v",err)
	}
	for _,val:=range comments{
		fmt.Printf("%#v",val)
	}
}

输出

2021-12-14 20:18:15 +0800 CST
1639484295
2021-12-14 21:20:16.129897 +0800 CST m=+0.088633101
1639488016
.....一些comment数据

问题3 mysql中的时间问题

我用gorm查询某个时间段的评论代码如下,可以看到我是以from和to 两个int64 类型,来作为查询条件,这是为了对应go中的unix时间戳也是int64

func ListComments(vid string ,from,to int64) ([]*defs.CommentWithName,error) {
	lock.RLock()
	defer lock.RUnlock()
	var res []*defs.CommentWithName
	dbConn.Debug().Raw("select comments.id,users.username,comments.content FROM comments "+
		"INNER JOIN users on comments.author_id=users.id where comments.video_id=? AND comments.created_at > FROM_UNIXTIME(?) AND "+
		"comments.created_at <= FROM_UNIXTIME(?)", vid, from, to).Scan(&res)
	return res,nil
}

但是他在Mysql内部执行的时候出了一些问题,什么问题呢,也是时区问题。
关键在于FROM_UNIXTIME(?)这个函数,他这个函数是将unix时间戳转为正常时间,这个正常时间是和时区有关的,你相同的unix时间戳转为不同时区的正常时间,它是不一样的

所导致的问题

这会导致一个什么问题,就是你在插入评论的时候,插入的created_at这个字段的值是你的时区时间,但是你在查找的时候,mysql调用FROM_UNIXTIME(?)这个函数转化的时间又是另外时区的时间,那么你查询的时候就会出问题。

基础命令熟悉

在实验之前,先准备一下基础的命令

FROM_UNIXTIME(unix_timestamp,format)
返回表示 Unix 时间标记的一个字符串,根据format字符串格式化。format可以包含与DATE_FORMAT()函数列出的条目同样的修饰符。
SELECT FROM_UNIXTIME(1234567890, '%Y-%m-%d %H:%i:%S')

正常时间格式转换成unix时间戳
select unix_timestamp(current_date);

show variables like "%time_zone%";
查看时区
±-----------------±-------+
| Variable_name | Value |
±-----------------±-------+
| system_time_zone | CST |
| time_zone | SYSTEM |
±-----------------±-------+
2 rows in set (0.00 sec)
#time_zone说明mysql使用system的时区,system_time_zone说明system使用CST时区
修改时区
set global time_zone = '+8:00';##修改mysql全局时区为北京时间,即我们所在的东8区
set time_zone = '+8:00'; ##临时修改,只用于当前会话
flush privileges; #立即生效

然后当你设置不同的时区的时候,把unix时间戳转为正常时间就会不一样

情况1 当时区为+8.00
system_time_zone
time_zone +08:00
执行
select from_unixtime(1639484295,'%Y-%m-%d %H:%i:%S')
得到 2021-12-14 20:18:15

情况2 当时区为+0.00
system_time_zone
time_zone +00:00
执行
select from_unixtime(1639484295,'%Y-%m-%d %H:%i:%S')
得到 2021-12-14 12:18:15 差了8个小时

因此即然时间不对,那么你去查找某一时间段的内容,当然也会找不出。

所以在使用这三个内容的时候需要注意时间问题


版权声明:本文为BlackNamePlate原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。