Source file
src/time/zoneinfo_windows.go
1
2
3
4
5 package time
6
7 import (
8 "errors"
9 "internal/syscall/windows/registry"
10 "runtime"
11 "syscall"
12 )
13
14 var zoneSources = []string{
15 runtime.GOROOT() + "/lib/time/zoneinfo.zip",
16 }
17
18
19
20
21
22
23
24
25
26
27
28 func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (matched bool, err2 error) {
29 k, err := registry.OpenKey(zones, kname, registry.READ)
30 if err != nil {
31 return false, err
32 }
33 defer k.Close()
34
35 var std, dlt string
36 if err = registry.LoadRegLoadMUIString(); err == nil {
37
38 std, err = k.GetMUIStringValue("MUI_Std")
39 if err == nil {
40 dlt, err = k.GetMUIStringValue("MUI_Dlt")
41 }
42 }
43 if err != nil {
44 if std, _, err = k.GetStringValue("Std"); err != nil {
45 return false, err
46 }
47 if dlt, _, err = k.GetStringValue("Dlt"); err != nil {
48 return false, err
49 }
50 }
51
52 if std != stdname {
53 return false, nil
54 }
55 if dlt != dstname && dstname != stdname {
56 return false, nil
57 }
58 return true, nil
59 }
60
61
62
63 func toEnglishName(stdname, dstname string) (string, error) {
64 k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
65 if err != nil {
66 return "", err
67 }
68 defer k.Close()
69
70 names, err := k.ReadSubKeyNames()
71 if err != nil {
72 return "", err
73 }
74 for _, name := range names {
75 matched, err := matchZoneKey(k, name, stdname, dstname)
76 if err == nil && matched {
77 return name, nil
78 }
79 }
80 return "", errors.New(`English name for time zone "` + stdname + `" not found in registry`)
81 }
82
83
84 func extractCAPS(desc string) string {
85 var short []rune
86 for _, c := range desc {
87 if 'A' <= c && c <= 'Z' {
88 short = append(short, c)
89 }
90 }
91 return string(short)
92 }
93
94
95 func abbrev(z *syscall.Timezoneinformation) (std, dst string) {
96 stdName := syscall.UTF16ToString(z.StandardName[:])
97 a, ok := abbrs[stdName]
98 if !ok {
99 dstName := syscall.UTF16ToString(z.DaylightName[:])
100
101 englishName, err := toEnglishName(stdName, dstName)
102 if err == nil {
103 a, ok = abbrs[englishName]
104 if ok {
105 return a.std, a.dst
106 }
107 }
108
109 return extractCAPS(stdName), extractCAPS(dstName)
110 }
111 return a.std, a.dst
112 }
113
114
115
116
117 func pseudoUnix(year int, d *syscall.Systemtime) int64 {
118
119
120
121
122
123 day := 1
124 t := Date(year, Month(d.Month), day, int(d.Hour), int(d.Minute), int(d.Second), 0, UTC)
125 i := int(d.DayOfWeek) - int(t.Weekday())
126 if i < 0 {
127 i += 7
128 }
129 day += i
130 if week := int(d.Day) - 1; week < 4 {
131 day += week * 7
132 } else {
133
134 day += 4 * 7
135 if day > daysIn(Month(d.Month), year) {
136 day -= 7
137 }
138 }
139 return t.sec() + int64(day-1)*secondsPerDay + internalToUnix
140 }
141
142 func initLocalFromTZI(i *syscall.Timezoneinformation) {
143 l := &localLoc
144
145 l.name = "Local"
146
147 nzone := 1
148 if i.StandardDate.Month > 0 {
149 nzone++
150 }
151 l.zone = make([]zone, nzone)
152
153 stdname, dstname := abbrev(i)
154
155 std := &l.zone[0]
156 std.name = stdname
157 if nzone == 1 {
158
159 std.offset = -int(i.Bias) * 60
160 l.cacheStart = alpha
161 l.cacheEnd = omega
162 l.cacheZone = std
163 l.tx = make([]zoneTrans, 1)
164 l.tx[0].when = l.cacheStart
165 l.tx[0].index = 0
166 return
167 }
168
169
170
171
172 std.offset = -int(i.Bias+i.StandardBias) * 60
173
174 dst := &l.zone[1]
175 dst.name = dstname
176 dst.offset = -int(i.Bias+i.DaylightBias) * 60
177 dst.isDST = true
178
179
180
181 d0 := &i.StandardDate
182 d1 := &i.DaylightDate
183 i0 := 0
184 i1 := 1
185 if d0.Month > d1.Month {
186 d0, d1 = d1, d0
187 i0, i1 = i1, i0
188 }
189
190
191 l.tx = make([]zoneTrans, 400)
192
193 t := Now().UTC()
194 year := t.Year()
195 txi := 0
196 for y := year - 100; y < year+100; y++ {
197 tx := &l.tx[txi]
198 tx.when = pseudoUnix(y, d0) - int64(l.zone[i1].offset)
199 tx.index = uint8(i0)
200 txi++
201
202 tx = &l.tx[txi]
203 tx.when = pseudoUnix(y, d1) - int64(l.zone[i0].offset)
204 tx.index = uint8(i1)
205 txi++
206 }
207 }
208
209 var usPacific = syscall.Timezoneinformation{
210 Bias: 8 * 60,
211 StandardName: [32]uint16{
212 'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'S', 't', 'a', 'n', 'd', 'a', 'r', 'd', ' ', 'T', 'i', 'm', 'e',
213 },
214 StandardDate: syscall.Systemtime{Month: 11, Day: 1, Hour: 2},
215 DaylightName: [32]uint16{
216 'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'D', 'a', 'y', 'l', 'i', 'g', 'h', 't', ' ', 'T', 'i', 'm', 'e',
217 },
218 DaylightDate: syscall.Systemtime{Month: 3, Day: 2, Hour: 2},
219 DaylightBias: -60,
220 }
221
222 var aus = syscall.Timezoneinformation{
223 Bias: -10 * 60,
224 StandardName: [32]uint16{
225 'A', 'U', 'S', ' ', 'E', 'a', 's', 't', 'e', 'r', 'n', ' ', 'S', 't', 'a', 'n', 'd', 'a', 'r', 'd', ' ', 'T', 'i', 'm', 'e',
226 },
227 StandardDate: syscall.Systemtime{Month: 4, Day: 1, Hour: 3},
228 DaylightName: [32]uint16{
229 'A', 'U', 'S', ' ', 'E', 'a', 's', 't', 'e', 'r', 'n', ' ', 'D', 'a', 'y', 'l', 'i', 'g', 'h', 't', ' ', 'T', 'i', 'm', 'e',
230 },
231 DaylightDate: syscall.Systemtime{Month: 10, Day: 1, Hour: 2},
232 DaylightBias: -60,
233 }
234
235 func initLocal() {
236 var i syscall.Timezoneinformation
237 if _, err := syscall.GetTimeZoneInformation(&i); err != nil {
238 localLoc.name = "UTC"
239 return
240 }
241 initLocalFromTZI(&i)
242 }
243
View as plain text