时区的问题

不同系统的时区配置文件不同 以 centos为例

配置文件

/etc/localtime  -> /usr/share/zoneinfo/...

$ ls /etc/localtime  -lh
/etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai

$ date -R
Fri, 12 Aug 2022 17:59:11 +0800

表示东八区

dockerfile 中设置时区


ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

gorm 使用时区

  • 连接串dsn中可以指定loc dsn := "admin:admin@tcp(192.168.156.100:3306)/gorm?charset=utf8&parseTime=True&loc=Local"
    从数据库中读出的时间的字符串,指定parseTime就将字符串解析成time格式
/Users/x/.gopath/src/github.com/go-sql-driver/mysql/packets.go
readRow() {
if !mc.parseTime {
  continue
    } else {
					switch rows.rs.columns[i].fieldType {
					case fieldTypeTimestamp, fieldTypeDateTime,
						fieldTypeDate, fieldTypeNewDate:
  dest[i], err = parseDateTime(
							string(dest[i].([]byte)),
							mc.cfg.Loc,
						)
if err == nil {
  continue
    }
default:
continue
  }
				}
}
    
/src/github.com/go-sql-driver/mysql/utils.go
func parseDateTime(str string, loc *time.Location) (t time.Time, err error) {
	base := "0000-00-00 00:00:00.0000000"
	switch len(str) {
	case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM"
if str == base[:len(str)] {
  return
    }
		t, err = time.Parse(timeFormat[:len(str)], str)
default:
  err = fmt.Errorf("invalid time string: %s", str)
return
  }

	// Adjust location
if err == nil && loc != time.UTC {
		y, mo, d := t.Date()
		h, mi, s := t.Clock()
		t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil
	}

  return
    }

不指定就会使用默认的,默认的也就是local

上边中:
		t, err = time.Parse(timeFormat[:len(str)], str)

func Parse(layout, value string) (Time, error) {
	return parse(layout, value, UTC, Local)
}
// Local represents the system's local time zone.
// On Unix systems, Local consults the TZ environment
// variable to find the time zone to use. No TZ means
// use the system default /etc/localtime.
// TZ="" means use UTC.
// TZ="foo" means use file foo in the system timezone directory.
var Local *Location = &localLoc

source code


package main

import (
  "encoding/json"
  "time"

  "github.com/zssky/log"
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
)

type TimeModel struct {
	T *time.Time `gorm:default:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;comment:'修改时间''"`
}

func (*TimeModel) TableName() string {
	return "vvv"
}

func dbInit() (*gorm.DB, error) {

	dsn := "admin:admin@tcp(192.168.156.100:3306)/gorm?charset=utf8&parseTime=True&loc=Local"
	return gorm.Open(mysql.New(mysql.Config{
		DSN:                       dsn,   // DSN data source name
		DefaultStringSize:         256,   // string 类型字段的默认长度
		DisableDatetimePrecision:  true,  // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,  // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,  // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
	}), &gorm.Config{})

}

func main() {
	db, err := dbInit()
	if err != nil {
		log.Error(err)
		return
	}
	r := TimeModel{}

	if err = db.Model(&TimeModel{}).First(&r).Error; err != nil {
		log.Error(err)
		return
	}
	o, e := json.Marshal(r)
	if e != nil {
		log.Error(err)
		return
	}
	log.Infof("%#v", *r.T)
	log.Info(string(o))
}

时区信息在第一次使用时间是加载

go/src/time/zoneinfo_unix.go

func (l *Location) get() *Location {
if l == nil {
  return &utcLoc
	}
if l == &localLoc {
		localOnce.Do(initLocal)
	}
  return l
    }

// Many systems use /usr/share/zoneinfo, Solaris 2 has
// /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ.
var zoneSources = []string{
	"/usr/share/zoneinfo/",
	"/usr/share/lib/zoneinfo/",
	"/usr/lib/locale/TZ/",
	runtime.GOROOT() + "/lib/time/zoneinfo.zip",
}

func initLocal() {
	// consult $TZ to find the time zone to use.
	// no $TZ means use the system default /etc/localtime.
	// $TZ="" means use UTC.
	// $TZ="foo" or $TZ=":foo" if foo is an absolute path, then the file pointed
	// by foo will be used to initialize timezone; otherwise, file
	// /usr/share/zoneinfo/foo will be used.

	tz, ok := syscall.Getenv("TZ")
	switch {
	case !ok:
		z, err := loadLocation("localtime", []string{"/etc"})
		if err == nil {
			localLoc = *z
			localLoc.name = "Local"
			return
		}
	case tz != "":
		if tz[0] == ':' {
			tz = tz[1:]
		}
		if tz != "" && tz[0] == '/' {
			if z, err := loadLocation(tz, []string{""}); err == nil {
				localLoc = *z
				if tz == "/etc/localtime" {
					localLoc.name = "Local"
				} else {
					localLoc.name = tz
				}
				return
			}
		} else if tz != "" && tz != "UTC" {
			if z, err := loadLocation(tz, zoneSources); err == nil {
				localLoc = *z
				return
			}
		}
	}

	// Fall back to UTC.
	localLoc.name = "UTC"
}

系统调用

rt_sigaction(SIGRT_32, {sa_handler=0x463fe0, sa_mask=~[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_RESTART|SA_SIGINFO, sa_restorer=0x464120}, NULL, 8) = 0
rt_sigprocmask(SIG_SETMASK, ~[], [], 8) = 0
clone(child_stack=0xc00008e000, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS, tls=0xc00007e090) = 245
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGURG {si_signo=SIGURG, si_code=SI_TKILL, si_pid=244, si_uid=0} ---
rt_sigreturn({mask=[]})                 = 0
--- SIGURG {si_signo=SIGURG, si_code=SI_TKILL, si_pid=244, si_uid=0} ---
rt_sigreturn({mask=[]})                 = 0
--- SIGURG {si_signo=SIGURG, si_code=SI_TKILL, si_pid=244, si_uid=0} ---
rt_sigreturn({mask=[]})                 = 10322680
rt_sigprocmask(SIG_SETMASK, ~[], [], 8) = 0
clone(child_stack=0xc000090000, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS, tls=0xc00007e490) = 246
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
futex(0xc00007e548, FUTEX_WAKE_PRIVATE, 1) = 1
rt_sigprocmask(SIG_SETMASK, ~[], [], 8) = 0
clone(child_stack=0xc00008a000, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS, tls=0xc00007e890) = 248
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
fcntl(0, F_GETFL)                       = 0x8002 (flags O_RDWR|O_LARGEFILE)
futex(0xc00007e948, FUTEX_WAKE_PRIVATE, 1) = 1
fcntl(1, F_GETFL)                       = 0x8002 (flags O_RDWR|O_LARGEFILE)
fcntl(2, F_GETFL)                       = 0x8002 (flags O_RDWR|O_LARGEFILE)
openat(AT_FDCWD, "/usr/share/zoneinfo//Asia/Shanghai", O_RDONLY) = 3
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\2\0\0\0\0"..., 4096) = 556
read(3, "", 4096)                       = 0
close(3)                                = 0
write(1, "2022/08/12 18:42:12 main.go:34: "..., 692022/08/12 18:42:12 main.go:34: info 0 "hello you see me"
) = 69
write(1, "2022/08/12 18:42:12 main.go:38: "..., 712022/08/12 18:42:12 main.go:38: info main "ttttttttttttttt"
) = 71
futex(0xc000100148, FUTEX_WAKE_PRIVATE, 1) = 1
socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("192.168.156.100")}, 16) = -1 EINPROGRESS (Operation now in progress)
epoll_create1(EPOLL_CLOEXEC)            = 4
pipe2([5, 6], O_NONBLOCK|O_CLOEXEC)     = 0
epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=10511816, u64=10511816}}) = 0
epoll_ctl(4, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=2261080856, u64=140525001071384}}) = 0
epoll_pwait(4, [], 128, 0, NULL, 2)     = 0
epoll_pwait(4, [{EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP|EPOLLRDHUP, {u32=2261080856, u64=140525001071384}}], 128, -1, NULL, 0) = 1
futex(0x9d83d8, FUTEX_WAKE_PRIVATE, 1)  = 1
futex(0x9d82f8, FUTEX_WAKE_PRIVATE, 1)  = 1
getsockopt(3, SOL_SOCKET, SO_ERROR, [110], [4]) = 0
epoll_ctl(4, EPOLL_CTL_DEL, 3, 0xc00015b04c) = 0
close(3)                                = 0
write(1, "\r\n2022/08/12 18:42:27 \33[35m/User"..., 219
2022/08/12 18:42:27 /Users/zhangqian458/git-jd/src/git.jd.com/drc/mytest/time/main.go:23
[error] failed to initialize database, got error dial tcp 192.168.156.100:3306: connect: connection timed out
) = 219
write(1, "2022/08/12 18:42:27 main.go:41: "..., 1172022/08/12 18:42:27 main.go:41: error main  dial tcp 192.168.156.100:3306: connect: connection timed out
) = 117
exit_group(0)                           = ?
+++ exited with 0 +++

data 命令的系统调用

execve("/usr/bin/date", ["date"], [/* 22 vars */]) = 0
brk(NULL)                               = 0x1f63000
    
...
    
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=103860, ...}) = 0
mmap(NULL, 103860, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff61912e000
close(3)                                = 0
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
fcntl(3, F_GETFD)                       = 0x1 (flags FD_CLOEXEC)
fstat(3, {st_mode=S_IFREG|0644, st_size=2492, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff61914e000
read(3, "# Locale name alias data base.\n#"..., 4096) = 2492
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7ff61914e000, 4096)            = 0
    
...
    
open("/etc/localtime", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=388, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=388, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff61914e000
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\2\0\0\0\0"..., 4096) = 388
lseek(3, -240, SEEK_CUR)                = 148
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\3\0\0\0\0"..., 4096) = 240
close(3)                                = 0
munmap(0x7ff61914e000, 4096)            = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff61914e000
write(1, "Fri Aug 12 18:00:25 CST 2022\n", 29Fri Aug 12 18:00:25 CST 2022
) = 29
close(1)                                = 0
munmap(0x7ff61914e000, 4096)            = 0
close(2)                                = 0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值