Slide 1

Slide 1 text

Go ͷ Timezone ͱ Go 1.15 ͷ tzdata ຒΊࠐΈ
 Remote.go #1
 Jul 17, 2020 Kanmu, Inc. Hiroaki Sano

Slide 2

Slide 2 text

2 ࠤ໺༟ষ Backend Engineer at Kanmu, Inc. @hiroakis hiroakis (@la_luna_azul)

Slide 3

Slide 3 text

3 όϯυϧΧʔυͭͬͯ͘·͢

Slide 4

Slide 4 text

Go 1.15 1

Slide 5

Slide 5 text

Go 1.15 5 1 • 2020೥8݄ʹϦϦʔε༧ఆ • ݱࡏ Go 1.15 Beta1 ͕ར༻Մೳ IUUQTUXJUUFSDPNHPMBOHTUBUVT

Slide 6

Slide 6 text

Go 1.15: Beta1 6 1 $ go get golang.org/dl/go1.15beta1 $ go1.15beta1 download $ go1.15beta1 version go version go1.15beta1 darwin/amd64

Slide 7

Slide 7 text

Go 1.15: DRAFT RELEASE NOTES 7 1 IUUQTUJQHPMBOHPSHEPDHP

Slide 8

Slide 8 text

Go ͷ Timezone 2

Slide 9

Slide 9 text

Go ͷ Timezone: Time ߏ଄ମͱ Now() 9 2 // Now returns the current local time. func Now() Time { sec, nsec, mono := now() mono -= startNano sec += unixToInternal - minWall if uint64(sec)>>33 != 0 { return Time{uint64(nsec), sec + minWall, Local} } return Time{hasMonotonic | uint64(sec)<

Slide 10

Slide 10 text

10 2 // Now returns the current local time. func Now() Time { sec, nsec, mono := now() mono -= startNano sec += unixToInternal - minWall if uint64(sec)>>33 != 0 { return Time{uint64(nsec), sec + minWall, Local} } return Time{hasMonotonic | uint64(sec)<

Slide 11

Slide 11 text

Go ͷ Timezone: Location ߏ଄ମ 11 2 var Local *Location = &localLoc
 var localLoc Location type Location struct { name string []zone []zone tx []zoneTrans cacheStart int64 cacheEnd []zoneint64 cacheZone *zone } var localOnce sync.Once func (l *Location) get() *Location { if l == nil { return &utcLoc } if l == &localLoc { localOnce.Do(initLocal) // <— initLocal ͸zoneinfo_xxx.go Ͱ֤؀ڥ͝ͱʹఆٛ } return l }

Slide 12

Slide 12 text

Go ͷ Timezone: Linux ͷ initLocal 12 2 var zoneSources = []string{ "/usr/share/zoneinfo/", "/usr/share/lib/zoneinfo/", "/usr/lib/locale/TZ/", runtime.GOROOT() + "/lib/time/zoneinfo.zip", } func initLocal() { 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 != "" && tz != "UTC": if z, err := loadLocation(tz, zoneSources); err == nil { localLoc = *z return } } localLoc.name = "UTC" } UJNF[POFJOGP@VOJYHP

Slide 13

Slide 13 text

Go ͷ Timezone: Windows ͷ initLocal 13 2 var zoneSources = []string{ runtime.GOROOT() + "/lib/time/zoneinfo.zip", } func initLocal() { var i syscall.Timezoneinformation if _, err := syscall.GetTimeZoneInformation(&i); err != nil { localLoc.name = "UTC" return } initLocalFromTZI(&i) } UJNF[POFJOGP@XJOEPXTHP

Slide 14

Slide 14 text

Go ͷ Timezone: Local Time ͷܾఆ 14 2 • ϩʔΧϧλΠϜ͸֤؀ڥͷ࣮૷ (zoneinfo_xxx.go) ͰॳظԽ • func (l *Location) get() ͕ݺ͹Εͨͱ͖ʹͦΕ͕ηοτ͞ΕΔ • l.get() ͸͍ͭݺ͹Ε͍ͯΔͷ͔ʁ • ͍͔ͭ͘ͷ৔ॴͰݺ͹Ε͍ͯΔɻtime.Time ΍ time.Location ͷ Stringer ΠϯλʔϑΣΠεͷ࣮૷ͳͲɻ • Linux ΛྫʹऔΔͱɺl.get() ͕ݺ͹Εͨͱ͖ʹ TZ ؀ڥม਺Λݩ ʹ /usr/share… ͳͲΛ୳͠ʹߦ͘ɻ

Slide 15

Slide 15 text

Timezoneͷมߋ 2

Slide 16

Slide 16 text

Timezone ͷมߋ 16 2 • ͍͔ͭ͘ͷखஈ • ϩʔΧϧλΠϜΛมߋ͢Δ • *Location Λඞཁͳͱ͖ʹ࡞ͬͯར༻͢Δ

Slide 17

Slide 17 text

Timezone ͷมߋ: Local Time Λมߋ͢Δ 17 2 • Linux ͷ৔߹ TZ ؀ڥม਺Λઃఆ͢Δ • ͨͩ͠ॳճͷΈ • sync.Once(initLocal) Ͱηοτ͞ΕΔͨΊ • ΞϓϦέʔγϣϯͷ࣮૷Ͱ var time.Local άϩʔόϧม਺ʹ *Location Λ୅ೖͯ͠͠·͏

Slide 18

Slide 18 text

Timezone ͷมߋ: *Location Λඞཁͳͱ͖ʹ࡞ͬͯར༻͢Δ 18 2 • *Location ΛಘΔ͍͔ͭ͘ͷAPI • func LoadLocation(name string) • func LoadLocationFromTZData(name string, data []byte) • func FixedZone(name string, offset int) • *Location ͷ࢖͍ํ • In(loc) • time.Now().In(loc) • time.Date(xxxx).In(loc) • …

Slide 19

Slide 19 text

Timezone ͷมߋ: func LoadLocation 19 2 func LoadLocation(name string) (*Location, error) { zoneinfoOnce.Do(func() { env, _ := syscall.Getenv("ZONEINFO") zoneinfo = &env }) var firstErr error if *zoneinfo != "" { if zoneData, err := loadTzinfoFromDirOrZip(*zoneinfo, name); err == nil { if z, err := LoadLocationFromTZData(name, zoneData); err == nil { return z, nil } firstErr = err } else if err != syscall.ENOENT { firstErr = err } } if z, err := loadLocation(name, zoneSources); err == nil { return z, nil } else if firstErr == nil { firstErr = err } return nil, firstErr }

Slide 20

Slide 20 text

20 2 • zoneSources Λ୳͠ʹ͍͘ • ࠷ॳʹݟ͔ͭͬͨ΍͕ͭద༻͞ΕΔ • ͳ͚Ε͹ΤϥʔʹͳΔ // time/zoneinfo_unix.go var zoneSources = []string{ "/usr/share/zoneinfo/", "/usr/share/lib/zoneinfo/", "/usr/lib/locale/TZ/", runtime.GOROOT() + "/lib/time/zoneinfo.zip", } // time/zoneinfo_windows.go var zoneSources = []string{ runtime.GOROOT() + "/lib/time/zoneinfo.zip", } Timezone ͷมߋ: func LoadLocation

Slide 21

Slide 21 text

Timezone ͷมߋ: ଞͷखஈ 21 2 • func LoadLocationFromTZData(name string, data []byte) • ࣗ෼Ͱ tzdata ͷੜσʔλΛ༻ҙ͓͍ͯͯ͠ಡ·ͤΔ • func FixedZone(name string, offset int) • ϩʔΧϧλΠϜ͔Βͷ offset Λϋʔυίʔυ͢Δ

Slide 22

Slide 22 text

Timezoneͷ໰୊఺ 3

Slide 23

Slide 23 text

23 3 • ؀ڥґଘ • Linux ͸ tzdata ͕ଘࡏ͍ͯ͠Δ͔ Go ͕Πϯετʔϧ͞Ε͍ͯ Δඞཁ͕͋Δ • Windows ͸ Go ͕Πϯετʔϧ͞Ε͍ͯΔඞཁ͕͋Δ Timezoneͷ໰୊఺

Slide 24

Slide 24 text

24 3 • ΞϓϦέʔγϣϯ഑෍ઌʹ tzdata ΛΠϯετʔϧ͓ͯ͘͠ • ΞϓϦέʔγϣϯ഑෍ઌʹ Go ΋Πϯετʔϧ͓ͯ͘͠ • ࣗ෼Ͱ tzdata Λ༻ҙͯ͠ LoadLocationFromTZData ͰಡΉ • FixedZone(name string, offset int)Λ࢖͏(ͨͩ͠αϚʔλΠϜ͕ ߟྀ͞Εͳ͍) Timezoneͷ໰୊఺: ղܾࡦ

Slide 25

Slide 25 text

Go 1.15 embedded tzdata package 4

Slide 26

Slide 26 text

Embedded tzdata package 26 4 IUUQTHJUIVCDPNHPMBOHHPJTTVFT

Slide 27

Slide 27 text

27 4 • Timezone ͷѻ͍ʹखஈ͕૿͑ͨ • ΞϓϦέʔγϣϯ഑෍ઌʹ tzdata ΛΠϯετʔϧ͓ͯ͘͠ • ΞϓϦέʔγϣϯ഑෍ઌʹ Go ΋Πϯετʔϧ͓ͯ͘͠ • ࣗ෼Ͱ tzdata Λ༻ҙͯ͠ LoadLocationFromTZData ͰಡΉ • Go 1.15 ͷ tzdata ຒΊࠐΈ Embedded tzdata package

Slide 28

Slide 28 text

28 4 IUUQTHPSFWJFXHPPHMFTPVSDFDPNDHPTSDUJNF[POFJOGP@SFBEHP Embedded tzdata package

Slide 29

Slide 29 text

29 4 IUUQTHPSFWJFXHPPHMFTPVSDFDPNDHPTSDUJNFU[EBUB[JQEBUBHP Embedded tzdata package

Slide 30

Slide 30 text

30 package main import ( "fmt" "log" "time" ) func main() { jst, err := time.LoadLocation("Asia/Tokyo") if err != nil { log.Fatal(err) } tm := time.Now().In(jst) fmt.Println(tm) } 4 Embedded tzdata package: σϞ

Slide 31

Slide 31 text

31 $ go build -o jst main.go $ ./jst 2020-07-11 16:42:00.588488 +0900 JST 4 Embedded tzdata package: σϞ

Slide 32

Slide 32 text

32 FROM alpine:latest WORKDIR /app COPY jst /app CMD ["/app/jst"] 4 Embedded tzdata package: σϞ

Slide 33

Slide 33 text

33 $ GOOS=linux go build -o jst main.go $ docker build -t jst:latest . $ docker run --rm jst:latest 2020/07/11 07:45:07 unknown time zone Asia/Tokyo 4 Embedded tzdata package: σϞ

Slide 34

Slide 34 text

34 package main import ( "fmt" "log" "time" _ "time/tzdata" ) func main() { jst, err := time.LoadLocation("Asia/Tokyo") if err != nil { log.Fatal(err) } tm := time.Now().In(jst) fmt.Println(tm) } 4 Embedded tzdata package: σϞ

Slide 35

Slide 35 text

35 $ GOOS=linux go1.15beta1 build -o jst main.go $ docker build -t jst:latest . $ docker run --rm jst:latest 2020-07-11 16:52:27.389673074 +0900 JST 4 Embedded tzdata package: σϞ

Slide 36

Slide 36 text

36 • छʑͷ؀ڥͰ࢖ΘΕΔιϑτ΢ΣΞΛ഑෍͢Δͱ͖ʹબ୒ࢶͱͯ͠ ༗༻ʹͳΓಘΔ • Α͘࢖ΘΕΔύοέʔδͷ಺෦Ͱ΋ LoadLocation ͸࢖ΘΕ͍ͯΔ • github.com/go-sql-driver/mysql • github.com/lib/pq • …etc • tzdata ͸͠͹͠͹ߋ৽͞ΕΔ • OSͳͲ౔୆ͰέΞ͢Δ͔ɺΞϓϦέʔγϣϯଆͰέΞ͢Δ͔ͷ ໰୊ͳͷͰಛੑΛΘ͔͍ͬͯΕ͹Α͍ 4 Embedded tzdata package

Slide 37

Slide 37 text

·ͱΊ 37 5 ·ͱΊ • Timezone ͸౔୆ͷ؀ڥʹґଘ͍ͯ͠Δ • Go1.15 ͔Β tzdata ຒΊࠐΈ͕Ͱ͖ΔΑ͏ʹͳΓ؀ڥґଘΛٵ ऩ͢Δखஈ͕૿͑Δ

Slide 38

Slide 38 text

͓ΘΓ