Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

os/gtime: There is a bug in converting string to gtime.Time #3558

Closed
wln32 opened this issue May 1, 2024 · 3 comments · Fixed by #3561
Closed

os/gtime: There is a bug in converting string to gtime.Time #3558

wln32 opened this issue May 1, 2024 · 3 comments · Fixed by #3561
Assignees
Labels
bug It is confirmed a bug, but don't worry, we'll handle it.

Comments

@wln32
Copy link
Member

wln32 commented May 1, 2024

Go version

1.22

GoFrame version

2.7.0

Can this bug be reproduced with the latest release?

Option Yes

What did you do?

t := gtime.NewFromStr("1880-10-24T00:00:00+08:05")

fmt.Println("1:", t.Format("Y-m-d"))
fmt.Println("2:", t)
t2, err := time.Parse(time.RFC3339, "1880-10-24T00:00:00+08:05")
fmt.Printf("3: time=[%s] err=%v\n", t2, err)

What did you see happen?

// output
// 1: 1880-10-23
// 2: 1880-10-23 15:55:00
// 3: time=[1880-10-24 00:00:00 +0805 +0805] err=<nil>
// 和标准库的解析不一样

What did you expect to see?

1: 1880-10-24
2: 1880-10-24 00:00:00
3: time=[1880-10-24 00:00:00 +0805 +0805] err=<nil>
@wln32 wln32 added the bug It is confirmed a bug, but don't worry, we'll handle it. label May 1, 2024
@Issues-translate-bot Issues-translate-bot changed the title os/gtime: 从字符串转成gtime.Time有bug os/gtime: There is a bug in converting string to gtime.Time May 1, 2024
@wln32 wln32 self-assigned this May 5, 2024
@wln32 wln32 linked a pull request May 5, 2024 that will close this issue
@wln32
Copy link
Member Author

wln32 commented May 6, 2024

在这里记录一下我是怎么发现这个bug的吧,起因是我在 #3557 中给底层重新实现类型转换的时候发现的,
在我的本地环境 ubuntu 20.04 mysql8 go 1.22 gf 2.7.0
测试没什么问题,但是提交pr后,CI 一直过不去,我看了日志发现有个测试,期望日期是1880-10-24,但是经过orm转换后变成了1880-10-23,看下图

1880-10-23

ci测试的连接

期初我以为是我的问题,我在我的本地环境又调试了一遍没发现什么问题,
于是我在 map=>struct 这一步加了日志,发现走到这步的时候,已经是1880-10-23了

dostruct-1880-10-23

ci测试的连接

这时候我已经发现可能是时区导致的问题了,于是我找到ci测试环境的mysql版本5.7.39,在我的本地装了一个同版本的

/*
		CREATE TABLE `timezone` (
		  `id` bigint(20) NOT NULL AUTO_INCREMENT,
		  `datetime` date DEFAULT NULL,
		  KEY `id` (`id`)
		) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

	*/
table := vm3306.Model("timezone")
_, err = table.Data(TimeZone{
	DateTime: gtime.NewFromStr("1880-10-24"),
}).Insert()

record, err := table.One()

在查询的底层加一个打印的

rowsto_struct

输出的结果

output1

可以和第一张图红圈上面的那个date做对比,上面图片的时区是UTC+0805,而这里的是+0800 CST 其实就是UTC+0800
其实这时候是没有什么问题的,因为mysql驱动对日期类型返回的是time.Time ,gf之前的做法对于time.Time类型直接返回的,并没有转为gtime.Time,date类型直接序列化为Y-m-d格式的,这时候由于是1880-10-24,测试没问题。

gf-convert-time

但是我在 #3557 中对于实现了sql.Scanner接口的类型,统一使用了sql.RawBytes接收,恰好gtime.Time实现了这个接口,
于是在我实现版本的中,解析过程就变成了 mysql驱动返回time.Time, 标准库把它转换sql.RawBytes,然后我接收到这个值,传给gtime.Time.Scan 方法,然后Scan方法最终调用gtime.StrToTime 来解析,
由于 ci测试环境下的mysql数据库返回的是UTC+08:05 和本地时区UTC+08:00(应该是go语言的有个单独的时区文件)经过比对发现时区不同 ,gtime.StrToTime会把时区转换为UTC+0时区,然后把对应的时钟分钟,根据+- 号来做加减,最后返回

zone-offset

这样就导致1880-10-24 00:00:00+08:05 解析后变成了1880-10-23 15:55:00Z,loc也是nil,等同于UTC+0

time-fromstr

这样的实现其实是错误的,对比同样字符串的看下go标准库的解析

std-time-format

由于gtime.Time丢失了时区信息,导致日期格式化Y-m-d的时候变成了1880-10-23

date-format

@wln32
Copy link
Member Author

wln32 commented May 6, 2024

@gqcn 我看到有好几个issue都是关于时区的问题,#1013 #1256 #1560 #1714 #2434 #3188 希望能够重视这个时区问题

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


@gqcn I saw several issues about time zone issues, #1013 #1256 #1560 #1714 #2434 #3188 I hope this time zone issue can be taken seriously.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug It is confirmed a bug, but don't worry, we'll handle it.
Projects
None yet
2 participants