github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/time/zoneinfo_windows.go (about) 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. 4 5 package time 6 7 import ( 8 "errors" 9 "runtime" 10 "syscall" 11 ) 12 13 // TODO(rsc): Fall back to copy of zoneinfo files. 14 15 // BUG(brainman,rsc): On Windows, the operating system does not provide complete 16 // time zone information. 17 // The implementation assumes that this year's rules for daylight savings 18 // time apply to all previous and future years as well. 19 // Also, time zone abbreviations are unavailable. The implementation constructs 20 // them using the capital letters from a longer time zone description. 21 22 // abbrev returns the abbreviation to use for the given zone name. 23 func abbrev(name []uint16) string { 24 // name is 'Pacific Standard Time' but we want 'PST'. 25 // Extract just capital letters. It's not perfect but the 26 // information we need is not available from the kernel. 27 // Because time zone abbreviations are not unique, 28 // Windows refuses to expose them. 29 // 30 // http://social.msdn.microsoft.com/Forums/eu/vclanguage/thread/a87e1d25-fb71-4fe0-ae9c-a9578c9753eb 31 // http://stackoverflow.com/questions/4195948/windows-time-zone-abbreviations-in-asp-net 32 var short []rune 33 for _, c := range name { 34 if 'A' <= c && c <= 'Z' { 35 short = append(short, rune(c)) 36 } 37 } 38 return string(short) 39 } 40 41 // pseudoUnix returns the pseudo-Unix time (seconds since Jan 1 1970 *LOCAL TIME*) 42 // denoted by the system date+time d in the given year. 43 // It is up to the caller to convert this local time into a UTC-based time. 44 func pseudoUnix(year int, d *syscall.Systemtime) int64 { 45 // Windows specifies daylight savings information in "day in month" format: 46 // d.Month is month number (1-12) 47 // d.DayOfWeek is appropriate weekday (Sunday=0 to Saturday=6) 48 // d.Day is week within the month (1 to 5, where 5 is last week of the month) 49 // d.Hour, d.Minute and d.Second are absolute time 50 day := 1 51 t := Date(year, Month(d.Month), day, int(d.Hour), int(d.Minute), int(d.Second), 0, UTC) 52 i := int(d.DayOfWeek) - int(t.Weekday()) 53 if i < 0 { 54 i += 7 55 } 56 day += i 57 if week := int(d.Day) - 1; week < 4 { 58 day += week * 7 59 } else { 60 // "Last" instance of the day. 61 day += 4 * 7 62 if day > daysIn(Month(d.Month), year) { 63 day -= 7 64 } 65 } 66 return t.sec + int64(day-1)*secondsPerDay + internalToUnix 67 } 68 69 func initLocalFromTZI(i *syscall.Timezoneinformation) { 70 l := &localLoc 71 72 nzone := 1 73 if i.StandardDate.Month > 0 { 74 nzone++ 75 } 76 l.zone = make([]zone, nzone) 77 78 std := &l.zone[0] 79 std.name = abbrev(i.StandardName[0:]) 80 if nzone == 1 { 81 // No daylight savings. 82 std.offset = -int(i.Bias) * 60 83 l.cacheStart = -1 << 63 84 l.cacheEnd = 1<<63 - 1 85 l.cacheZone = std 86 l.tx = make([]zoneTrans, 1) 87 l.tx[0].when = l.cacheStart 88 l.tx[0].index = 0 89 return 90 } 91 92 // StandardBias must be ignored if StandardDate is not set, 93 // so this computation is delayed until after the nzone==1 94 // return above. 95 std.offset = -int(i.Bias+i.StandardBias) * 60 96 97 dst := &l.zone[1] 98 dst.name = abbrev(i.DaylightName[0:]) 99 dst.offset = -int(i.Bias+i.DaylightBias) * 60 100 dst.isDST = true 101 102 // Arrange so that d0 is first transition date, d1 second, 103 // i0 is index of zone after first transition, i1 second. 104 d0 := &i.StandardDate 105 d1 := &i.DaylightDate 106 i0 := 0 107 i1 := 1 108 if d0.Month > d1.Month { 109 d0, d1 = d1, d0 110 i0, i1 = i1, i0 111 } 112 113 // 2 tx per year, 100 years on each side of this year 114 l.tx = make([]zoneTrans, 400) 115 116 t := Now().UTC() 117 year := t.Year() 118 txi := 0 119 for y := year - 100; y < year+100; y++ { 120 tx := &l.tx[txi] 121 tx.when = pseudoUnix(y, d0) - int64(l.zone[i1].offset) 122 tx.index = uint8(i0) 123 txi++ 124 125 tx = &l.tx[txi] 126 tx.when = pseudoUnix(y, d1) - int64(l.zone[i0].offset) 127 tx.index = uint8(i1) 128 txi++ 129 } 130 } 131 132 var usPacific = syscall.Timezoneinformation{ 133 Bias: 8 * 60, 134 StandardName: [32]uint16{ 135 'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'S', 't', 'a', 'n', 'd', 'a', 'r', 'd', ' ', 'T', 'i', 'm', 'e', 136 }, 137 StandardDate: syscall.Systemtime{Month: 11, Day: 1, Hour: 2}, 138 DaylightName: [32]uint16{ 139 'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'D', 'a', 'y', 'l', 'i', 'g', 'h', 't', ' ', 'T', 'i', 'm', 'e', 140 }, 141 DaylightDate: syscall.Systemtime{Month: 3, Day: 2, Hour: 2}, 142 DaylightBias: -60, 143 } 144 145 func initTestingZone() { 146 initLocalFromTZI(&usPacific) 147 } 148 149 func initLocal() { 150 var i syscall.Timezoneinformation 151 if _, err := syscall.GetTimeZoneInformation(&i); err != nil { 152 localLoc.name = "UTC" 153 return 154 } 155 initLocalFromTZI(&i) 156 } 157 158 func loadLocation(name string) (*Location, error) { 159 if z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name); err == nil { 160 z.name = name 161 return z, nil 162 } 163 return nil, errors.New("unknown time zone " + name) 164 }