时区问题需要考虑几个因素,操作系统时区环境,代码时区,数据库时区
操作系统时区
通常操作系统根据 /etc/localtime 确定时区。对于东八区此文件一般可以从 /usr/share/zoneinfo/Asia/Shanghai 拷贝出来,或者链接到此文件。
/etc/localtime 文件可以确定时区的原因在于:
- 时区数据:/etc/localtime 链接到的文件包含了该系统所在时区的具体信息,如相对于UTC的偏移量、夏令时规则等。
- 系统时间设置:操作系统使用这个文件来确定系统时间、日期和相关的时间设置。当系统需要显示或处理时间时,它会参考这个文件中的时区信息来转换为本地时间。
- 应用程序兼容性:许多应用程序在处理时间时会依赖 /etc/localtime 文件来确保它们显示和存储的时间是正确的,符合用户的本地时区设置。
代码时区(以 golang 为例子)
在解析时间,格式化时间时,可以指定时区,从而使时间带有时区信息
import (
"fmt"
"testing"
"time"
)
func TestTimeConvert(t *testing.T) {
// 原始时间字符串,带有 +08:00 时区偏移
timeStr := "2020-01-01T21:30:03+02:00"
// 定义时间的布局,这个布局与 RFC 3339 标准一致
layout := time.RFC3339
// 解析原始时间字符串为 time.Time 对象
parsedTime, err := time.ParseInLocation(layout, timeStr, time.UTC)
if err != nil {
fmt.Println("Error parsing time:", err)
return
}
// 打印 UTC 时间
fmt.Println("time:", parsedTime)
fmt.Println("RFC3339 format time:", parsedTime.Format(layout))
fmt.Println("RFC3339 format in UTC time:", parsedTime.In(time.UTC).Format(layout))
fmt.Println("DateTime format time:", parsedTime.Format(time.DateTime))
fmt.Println("DateTime format in UTC time:", parsedTime.In(time.UTC).Format(time.DateTime))
运行结果
time: 2020-01-01 21:30:03 +0200 +0200
RFC3339 format time: 2020-01-01T21:30:03+02:00
RFC3339 format in UTC time: 2020-01-01T19:30:03Z
DateTime format time: 2020-01-01 21:30:03
DateTime format in UTC time: 2020-01-01 19:30:03
数据库时区
数据库有库的默认时区,是启动整个数据库时候指定的时区,对于 current timestamp 自动填充的,或者系统表的数据的时区都是依据数据库时区填充的。
session 时区,在 dbsource 指定的时区,可以指定 local,或者具体的时区,对于 gorm 可以参考下面的例子。
xxx?charset=utf8mb4&parseTime=true&loc=UTC"
?charset=utf8mb4&parseTime=true&loc=Local"
?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
时区字段大小写对不上可能报错