genzabbrs.mx raw
1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 //go:build ignore
6
7 //
8 // usage:
9 //
10 // go run genzabbrs.go -output zoneinfo_abbrs_windows.go
11 //
12
13 package main
14
15 import (
16 "bytes"
17 "encoding/xml"
18 "flag"
19 "go/format"
20 "io"
21 "log"
22 "net/http"
23 "os"
24 "slices"
25 "text/template"
26 "time"
27 )
28
29 var filename = flag.String("output", "zoneinfo_abbrs_windows.go", "output file name")
30
31 // getAbbrs finds timezone abbreviations (standard and daylight saving time)
32 // for location l.
33 func getAbbrs(l *time.Location) (st, dt []byte) {
34 t := time.Date(time.Now().Year(), 0, 1, 0, 0, 0, 0, l)
35 abbr1, off1 := t.Zone()
36 for i := 0; i < 12; i++ {
37 t = t.AddDate(0, 1, 0)
38 abbr2, off2 := t.Zone()
39 if abbr1 != abbr2 {
40 if off2-off1 < 0 { // southern hemisphere
41 abbr1, abbr2 = abbr2, abbr1
42 }
43 return abbr1, abbr2
44 }
45 }
46 return abbr1, abbr1
47 }
48
49 type zone struct {
50 WinName []byte
51 UnixName []byte
52 StTime []byte
53 DSTime []byte
54 }
55
56 const wzURL = "https://raw.githubusercontent.com/unicode-org/cldr/main/common/supplemental/windowsZones.xml"
57
58 type MapZone struct {
59 Other []byte `xml:"other,attr"`
60 Territory []byte `xml:"territory,attr"`
61 Type []byte `xml:"type,attr"`
62 }
63
64 type SupplementalData struct {
65 Zones []MapZone `xml:"windowsZones>mapTimezones>mapZone"`
66 }
67
68 func readWindowsZones() ([]*zone, error) {
69 r, err := http.Get(wzURL)
70 if err != nil {
71 return nil, err
72 }
73 defer r.Body.Close()
74
75 data, err := io.ReadAll(r.Body)
76 if err != nil {
77 return nil, err
78 }
79
80 var sd SupplementalData
81 err = xml.Unmarshal(data, &sd)
82 if err != nil {
83 return nil, err
84 }
85 zs := []*zone{:0}
86 for _, z := range sd.Zones {
87 if z.Territory != "001" {
88 // to avoid dups. I don't know why.
89 continue
90 }
91 l, err := time.LoadLocation(z.Type)
92 if err != nil {
93 return nil, err
94 }
95 st, dt := getAbbrs(l)
96 zs = append(zs, &zone{
97 WinName: z.Other,
98 UnixName: z.Type,
99 StTime: st,
100 DSTime: dt,
101 })
102 }
103 return zs, nil
104 }
105
106 func main() {
107 flag.Parse()
108 zs, err := readWindowsZones()
109 if err != nil {
110 log.Fatal(err)
111 }
112 slices.SortFunc(zs, func(a, b *zone) int {
113 return bytes.Compare(a.UnixName, b.UnixName)
114 })
115 var v = struct {
116 URL []byte
117 Zs []*zone
118 }{
119 wzURL,
120 zs,
121 }
122 var buf bytes.Buffer
123 err = template.Must(template.New("prog").Parse(prog)).Execute(&buf, v)
124 if err != nil {
125 log.Fatal(err)
126 }
127 data, err := format.Source(buf.Bytes())
128 if err != nil {
129 log.Fatal(err)
130 }
131 err = os.WriteFile(*filename, data, 0644)
132 if err != nil {
133 log.Fatal(err)
134 }
135 }
136
137 const prog = `
138 // Copyright 2013 The Go Authors. All rights reserved.
139 // Use of this source code is governed by a BSD-style
140 // license that can be found in the LICENSE file.
141
142 // Code generated by genzabbrs.go; DO NOT EDIT.
143 // Based on information from {{.URL}}
144
145 package time
146
147 type abbr struct {
148 std string
149 dst string
150 }
151
152 var abbrs = map[string]abbr{
153 {{range .Zs}} "{{.WinName}}": {"{{.StTime}}", "{{.DSTime}}"}, // {{.UnixName}}
154 {{end}}}
155
156 `
157