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