Merge from mainline (167278:168000).
[official-gcc/graphite-test-results.git] / libgo / go / time / zoneinfo_windows.go
blobc357eec62b16a76bd9c9c4373787c8a1147b2636
1 // Copyright 2009 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.
5 package time
7 import (
8 "syscall"
9 "sync"
10 "os"
13 // BUG(brainman): The Windows implementation assumes that
14 // this year's rules for daylight savings time apply to all previous
15 // and future years as well.
17 // TODO(brainman): use GetDynamicTimeZoneInformation, whenever posible (Vista and up),
18 // to improve on situation described in the bug above.
20 type zone struct {
21 name string
22 offset int
23 year int64
24 month, day, dayofweek int
25 hour, minute, second int
26 abssec int64
27 prev *zone
30 // Populate zone struct with Windows supplied information. Returns true, if data is valid.
31 func (z *zone) populate(bias, biasdelta int32, d *syscall.Systemtime, name []uint16) (dateisgood bool) {
32 z.name = syscall.UTF16ToString(name)
33 z.offset = int(bias)
34 z.year = int64(d.Year)
35 z.month = int(d.Month)
36 z.day = int(d.Day)
37 z.dayofweek = int(d.DayOfWeek)
38 z.hour = int(d.Hour)
39 z.minute = int(d.Minute)
40 z.second = int(d.Second)
41 dateisgood = d.Month != 0
42 if dateisgood {
43 z.offset += int(biasdelta)
45 z.offset = -z.offset * 60
46 return
49 // Pre-calculte cutoff time in seconds since the Unix epoch, if data is supplied in "absolute" format.
50 func (z *zone) preCalculateAbsSec() {
51 if z.year != 0 {
52 z.abssec = (&Time{z.year, int(z.month), int(z.day), int(z.hour), int(z.minute), int(z.second), 0, 0, ""}).Seconds()
53 // Time given is in "local" time. Adjust it for "utc".
54 z.abssec -= int64(z.prev.offset)
58 // Convert zone cutoff time to sec in number of seconds since the Unix epoch, given particualar year.
59 func (z *zone) cutoffSeconds(year int64) int64 {
60 // Windows specifies daylight savings information in "day in month" format:
61 // z.month is month number (1-12)
62 // z.dayofweek is appropriate weekday (Sunday=0 to Saturday=6)
63 // z.day is week within the month (1 to 5, where 5 is last week of the month)
64 // z.hour, z.minute and z.second are absolute time
65 t := &Time{year, int(z.month), 1, int(z.hour), int(z.minute), int(z.second), 0, 0, ""}
66 t = SecondsToUTC(t.Seconds())
67 i := int(z.dayofweek) - t.Weekday
68 if i < 0 {
69 i += 7
71 t.Day += i
72 if week := int(z.day) - 1; week < 4 {
73 t.Day += week * 7
74 } else {
75 // "Last" instance of the day.
76 t.Day += 4 * 7
77 if t.Day > months(year)[t.Month] {
78 t.Day -= 7
81 // Result is in "local" time. Adjust it for "utc".
82 return t.Seconds() - int64(z.prev.offset)
85 // Is t before the cutoff for switching to z?
86 func (z *zone) isBeforeCutoff(t *Time) bool {
87 var coff int64
88 if z.year == 0 {
89 // "day in month" format used
90 coff = z.cutoffSeconds(t.Year)
91 } else {
92 // "absolute" format used
93 coff = z.abssec
95 return t.Seconds() < coff
98 type zoneinfo struct {
99 disabled bool // daylight saving time is not used localy
100 offsetIfDisabled int
101 januaryIsStd bool // is january 1 standard time?
102 std, dst zone
105 // Pick zone (std or dst) t time belongs to.
106 func (zi *zoneinfo) pickZone(t *Time) *zone {
107 z := &zi.std
108 if tz.januaryIsStd {
109 if !zi.dst.isBeforeCutoff(t) && zi.std.isBeforeCutoff(t) {
110 // after switch to daylight time and before the switch back to standard
111 z = &zi.dst
113 } else {
114 if zi.std.isBeforeCutoff(t) || !zi.dst.isBeforeCutoff(t) {
115 // before switch to standard time or after the switch back to daylight
116 z = &zi.dst
119 return z
122 var tz zoneinfo
123 var initError os.Error
124 var onceSetupZone sync.Once
126 func setupZone() {
127 var i syscall.Timezoneinformation
128 if _, e := syscall.GetTimeZoneInformation(&i); e != 0 {
129 initError = os.NewSyscallError("GetTimeZoneInformation", e)
130 return
132 if !tz.std.populate(i.Bias, i.StandardBias, &i.StandardDate, i.StandardName[0:]) {
133 tz.disabled = true
134 tz.offsetIfDisabled = tz.std.offset
135 return
137 tz.std.prev = &tz.dst
138 tz.dst.populate(i.Bias, i.DaylightBias, &i.DaylightDate, i.DaylightName[0:])
139 tz.dst.prev = &tz.std
140 tz.std.preCalculateAbsSec()
141 tz.dst.preCalculateAbsSec()
142 // Is january 1 standard time this year?
143 t := UTC()
144 tz.januaryIsStd = tz.dst.cutoffSeconds(t.Year) < tz.std.cutoffSeconds(t.Year)
147 // Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
148 func lookupTimezone(sec int64) (zone string, offset int) {
149 onceSetupZone.Do(setupZone)
150 if initError != nil {
151 return "", 0
153 if tz.disabled {
154 return "", tz.offsetIfDisabled
156 t := SecondsToUTC(sec)
157 z := &tz.std
158 if tz.std.year == 0 {
159 // "day in month" format used
160 z = tz.pickZone(t)
161 } else {
162 // "absolute" format used
163 if tz.std.year == t.Year {
164 // we have rule for the year in question
165 z = tz.pickZone(t)
166 } else {
167 // we do not have any information for that year,
168 // will assume standard offset all year around
171 return z.name, z.offset
174 // lookupByName returns the time offset for the
175 // time zone with the given abbreviation. It only considers
176 // time zones that apply to the current system.
177 func lookupByName(name string) (off int, found bool) {
178 onceSetupZone.Do(setupZone)
179 if initError != nil {
180 return 0, false
182 if tz.disabled {
183 return tz.offsetIfDisabled, false
185 switch name {
186 case tz.std.name:
187 return tz.std.offset, true
188 case tz.dst.name:
189 return tz.dst.offset, true
191 return 0, false