Golang time.Format 时间少了8小时?

1. 前端传参


可知前端使用 new Date().toISOString() 方法
该方法会将时间转换为 UTC 标准时间

2. 后台收参


注意看上面这张图的右边, 比较有意思
代码是这样的:

	if start != nil {
		query.Where("front_account_info.created_at>?", start)
		countSql += " and a.created_at > '" + start.In(time.Local).Format("2006-01-02 15:04:05") + "'"
		logger.Debug("带Local格式化时间:", start.In(time.Local).Format("2006-01-02 15:04:05"))
		logger.Debug("直接格式化时间:", start.Format("2006-01-02 15:04:05"))
	}

3. 通过比对得出结论

  • time.Format 函数在直接调用的时候是会处理时区信息的 (前端传参有带上时区信息为 UTC 时间, 需要转换为+8时间)
  • start 本身是带着时区信息的, 可以看上图 []interface{} 传参部分中的 time.Date(2022, time.February, 28, 16, 0, 0, 0, time.UTC), time.UTC即为时区信息
  • 需要带本地时区的 Format, 即 GMT+8 的, 必须调用 time.In(time.Local).Format() 或者 time.Local().Format(), 在time包源码中可得知这两种是等效的
// Local returns t with the location set to local time.
func (t Time) Local() Time {
	t.setLoc(Local)
	return t
}

// In returns a copy of t representing the same time instant, but
// with the copy's location information set to loc for display
// purposes.
//
// In panics if loc is nil.
func (t Time) In(loc *Location) Time {
	if loc == nil {
		panic("time: missing Location in call to Time.In")
	}
	t.setLoc(loc)
	return t
}

4. 结论

  • 有 orm 的情况下不要使用裸SQL
  • 裸SQL避免不了的情况下不要使用 time.Format, 除非传过来的是 +8 时区
  • 裸SQL+时间都避免不了的情况下, 一定使用 time.In(time.Local).Format() 进行本地时区转换
posted @ 2023-03-14 14:15  GETTOLIVE  阅读(630)  评论(0编辑  收藏  举报