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