😺
goでの基本的なtimezoneの決定方法をしらべてみた
- 2年ぐらい前に調べた物のメモ
- 探すとき大変なのでこちらにもうつす
timezoneはどこで決定されるのか
- /usr/local/go/src/time/zoneinfo.go
- このgetが呼び出されたときに決定される
- Onceは実行中一度しか呼び出されない
- つまり最初にget()が呼び出された瞬間に決定される
87 func (l *Location) get() *Location {
88 if l == nil {
89 return &utcLoc
90 }
91 if l == &localLoc {
92 localOnce.Do(initLocal)
93 }
94 return l
95 }
initLocalでは環境がどのように作用しているのか?
- zoneinfo_unix.go
28 func initLocal() {
29 // consult $TZ to find the time zone to use.
30 // no $TZ means use the system default /etc/localtime.
31 // $TZ="" means use UTC.
32 // $TZ="foo" means use /usr/share/zoneinfo/foo.
33
34 tz, ok := syscall.Getenv("TZ")
35 switch {
36 case !ok:
37 z, err := loadLocation("localtime", []string{"/etc"})
38 if err == nil {
39 localLoc = *z
40 localLoc.name = "Local"
41 return
42 }
43 case tz != "" && tz != "UTC":
44 if z, err := loadLocation(tz, zoneSources); err == nil {
45 localLoc = *z
46 return
47 }
48 }
49
50 // Fall back to UTC.
51 localLoc.name = "UTC"
52 }
- 大きく分けて処理は2つに分かれる
- 環境変数TZが無い場合
- 環境変数TZが有る場合
環境変数TZが無い場合
- 結論:無い場合は/etc/localtimeが適切に設定されていればそこに準拠した動作になります
- この場合はシステムの
- /etc/localtimeを見に行きます
- 自分のMacの場合localtimeにAsia/Tokyoへのリンクが張られています
ls -al /etc/localtime
lrwxr-xr-x 36 root 5 8 10:02 /etc/localtime -> /var/db/timezone/zoneinfo/Asia/Tokyo
環境変数TZが有る場合
- 結論:有る場合は以下のzoneSourcesを順に探していきます
- 例えばalpineの場合はtzdataをインストールした場合
- /usr/share/zoneinfo/にAsia/Tokyoが存在することになるので
- TZをAsia/TokyoにしておけばJSTになります
21 var zoneSources = []string{
22 "/usr/share/zoneinfo/",
23 "/usr/share/lib/zoneinfo/",
24 "/usr/lib/locale/TZ/",
25 runtime.GOROOT() + "/lib/time/zoneinfo.zip",
26 }
mysql driverの場合
- mysql driverでlocを設定した場合
- どうなるのか。
- dsn.goでconfigに設定される
450 // Time Location
451 case "loc":
452 if value, err = url.QueryUnescape(value); err != nil {
453 return
454 }
455 cfg.Loc, err = time.LoadLocation(value)
456 if err != nil {
457 return
458 }
- ZONEINFO環境変数などが設定されていない場合に関しては
- locに設定した値を元に
- loadLocationが呼び出される
.656 if z, err := loadLocation(name, zoneSources); err == nil {
657 return z, nil
658 } else if firstErr == nil {
659 firstErr = err
660 }
661 return nil, firstErr
locの設定はどこで使用されているか
- https://github.com/go-sql-driver/mysql
- packets.go
- parseTimeのオプションが設定されていた場合に
- parseDateTimeに使用されています
774 if !mc.parseTime {
775 continue
776 } else {
777 switch rows.rs.columns[i].fieldType {
778 case fieldTypeTimestamp, fieldTypeDateTime,
779 fieldTypeDate, fieldTypeNewDate:
780 dest[i], err = parseDateTime(
781 dest[i].([]byte),
782 mc.cfg.Loc,
783 )
784 if err == nil {
785 continue
786 }
787 default:
788 continue
789 }
Discussion