LEFT | RIGHT |
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package time | 5 package time |
6 | 6 |
7 import "sync" | 7 import "sync" |
8 | 8 |
9 // A Location maps time instants to the zone in use at that time. | 9 // A Location maps time instants to the zone in use at that time. |
10 // Typically, the Location represents the collection of time offsets | 10 // Typically, the Location represents the collection of time offsets |
11 // in use in a geographical area, such as CEST and CET for central Europe. | 11 // in use in a geographical area, such as CEST and CET for central Europe. |
12 type Location struct { | 12 type Location struct { |
13 name string | 13 name string |
14 zone []zone | 14 zone []zone |
15 tx []zoneTrans | 15 tx []zoneTrans |
16 | 16 |
17 // Most lookups will be for the current time. | 17 // Most lookups will be for the current time. |
18 // To avoid the binary search through tx, keep a | 18 // To avoid the binary search through tx, keep a |
19 // static one-element cache that gives the correct | 19 // static one-element cache that gives the correct |
20 // zone for the time when the Location was created. | 20 // zone for the time when the Location was created. |
21 // if cacheStart <= t <= cacheEnd, | 21 // if cacheStart <= t <= cacheEnd, |
22 » // Lookup can return cacheZone. | 22 » // lookup can return cacheZone. |
23 // The units for cacheStart and cacheEnd are seconds | 23 // The units for cacheStart and cacheEnd are seconds |
24 // since January 1, 1970 UTC, to match the argument | 24 // since January 1, 1970 UTC, to match the argument |
25 » // to Lookup. | 25 » // to lookup. |
26 cacheStart int64 | 26 cacheStart int64 |
27 cacheEnd int64 | 27 cacheEnd int64 |
28 cacheZone *zone | 28 cacheZone *zone |
29 } | 29 } |
30 | 30 |
31 // A zone represents a single time zone such as EST or EDT. | 31 // A zone represents a single time zone such as CEST or CET. |
32 type zone struct { | 32 type zone struct { |
33 » name string // short name, "EST" | 33 » name string // abbreviated name, "CET" |
34 offset int // seconds east of UTC | 34 offset int // seconds east of UTC |
35 isDST bool // is this zone Daylight Savings Time? | 35 isDST bool // is this zone Daylight Savings Time? |
36 } | 36 } |
37 | 37 |
38 // A zoneTrans represents a single time zone transition. | 38 // A zoneTrans represents a single time zone transition. |
39 type zoneTrans struct { | 39 type zoneTrans struct { |
40 when int64 // transition time, in seconds since 1970 GMT | 40 when int64 // transition time, in seconds since 1970 GMT |
41 index uint8 // the index of the zone that goes into effect at tha
t time | 41 index uint8 // the index of the zone that goes into effect at tha
t time |
42 isstd, isutc bool // ignored - no idea what these mean | 42 isstd, isutc bool // ignored - no idea what these mean |
43 } | 43 } |
44 | 44 |
45 // UTC represents Universal Coordinated Time (UTC). | 45 // UTC represents Universal Coordinated Time (UTC). |
46 var UTC *Location = &utcLoc | 46 var UTC *Location = &utcLoc |
47 | 47 |
| 48 // utcLoc is separate so that get can refer to &utcLoc |
| 49 // and ensure that it never returns a nil *Location, |
| 50 // even if a badly behaved client has changed UTC. |
48 var utcLoc = Location{name: "UTC"} | 51 var utcLoc = Location{name: "UTC"} |
49 | 52 |
50 // Local represents the system's local time zone. | 53 // Local represents the system's local time zone. |
51 var Local *Location = &localLoc | 54 var Local *Location = &localLoc |
52 | 55 |
| 56 // localLoc is separate so that initLocal can initialize |
| 57 // it even if a client has changed Local. |
53 var localLoc Location | 58 var localLoc Location |
54 var localOnce sync.Once | 59 var localOnce sync.Once |
55 | 60 |
56 func (l *Location) get() *Location { | 61 func (l *Location) get() *Location { |
57 if l == nil { | 62 if l == nil { |
58 return &utcLoc | 63 return &utcLoc |
59 } | 64 } |
60 if l == &localLoc { | 65 if l == &localLoc { |
61 localOnce.Do(initLocal) | 66 localOnce.Do(initLocal) |
62 } | 67 } |
63 return l | 68 return l |
64 } | 69 } |
65 | 70 |
66 // String returns a descriptive name for the time zone information, | 71 // String returns a descriptive name for the time zone information, |
67 // corresponding to the argument to LoadLocation. | 72 // corresponding to the argument to LoadLocation. |
68 func (l *Location) String() string { | 73 func (l *Location) String() string { |
69 return l.get().name | 74 return l.get().name |
70 } | 75 } |
71 | 76 |
72 // FixedZone returns a Location with a Lookup method | 77 // FixedZone returns a Location that always uses |
73 // that always returns the given name and offset. | 78 // the given zone name and offset (seconds east of UTC). |
74 func FixedZone(name string, offset int) *Location { | 79 func FixedZone(name string, offset int) *Location { |
75 l := &Location{ | 80 l := &Location{ |
76 name: name, | 81 name: name, |
77 zone: []zone{{name, offset, false}}, | 82 zone: []zone{{name, offset, false}}, |
78 tx: []zoneTrans{{-1 << 63, 0, false, false}}, | 83 tx: []zoneTrans{{-1 << 63, 0, false, false}}, |
79 cacheStart: -1 << 63, | 84 cacheStart: -1 << 63, |
80 cacheEnd: 1<<63 - 1, | 85 cacheEnd: 1<<63 - 1, |
81 } | 86 } |
82 l.cacheZone = &l.zone[0] | 87 l.cacheZone = &l.zone[0] |
83 return l | 88 return l |
84 } | 89 } |
85 | 90 |
86 // Lookup returns information about the time zone in use at an | 91 // lookup returns information about the time zone in use at an |
87 // instant in time expressed as seconds since January 1, 1970 00:00:00 UTC. | 92 // instant in time expressed as seconds since January 1, 1970 00:00:00 UTC. |
88 // | 93 // |
89 // The returned information gives the name of the zone (such as "EST"), | 94 // The returned information gives the name of the zone (such as "CET"), |
90 // the start and end times bracketing sec when that zone is in effect, | 95 // the start and end times bracketing sec when that zone is in effect, |
91 // the offset in seconds east of UTC (such as -5*60*60), and whether | 96 // the offset in seconds east of UTC (such as -5*60*60), and whether |
92 // the daylight savings is being observed at that time. | 97 // the daylight savings is being observed at that time. |
93 func (l *Location) Lookup(sec int64) (name string, offset int, isDST bool, start
, end int64) { | 98 func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start
, end int64) { |
94 l = l.get() | 99 l = l.get() |
95 | 100 |
96 if len(l.tx) == 0 { | 101 if len(l.tx) == 0 { |
97 name = "UTC" | 102 name = "UTC" |
98 offset = 0 | 103 offset = 0 |
99 isDST = false | 104 isDST = false |
100 start = -1 << 63 | 105 start = -1 << 63 |
101 end = 1<<63 - 1 | 106 end = 1<<63 - 1 |
102 return | 107 return |
103 } | 108 } |
(...skipping 23 matching lines...) Expand all Loading... |
127 } | 132 } |
128 zone := &l.zone[tx[0].index] | 133 zone := &l.zone[tx[0].index] |
129 name = zone.name | 134 name = zone.name |
130 offset = zone.offset | 135 offset = zone.offset |
131 isDST = zone.isDST | 136 isDST = zone.isDST |
132 start = tx[0].when | 137 start = tx[0].when |
133 // end = maintained during the search | 138 // end = maintained during the search |
134 return | 139 return |
135 } | 140 } |
136 | 141 |
137 // LookupName returns information about the time zone with | 142 // lookupName returns information about the time zone with |
138 // the given name (such as "EST"). | 143 // the given name (such as "EST"). |
139 func (l *Location) LookupName(name string) (offset int, isDST bool, ok bool) { | 144 func (l *Location) lookupName(name string) (offset int, isDST bool, ok bool) { |
140 l = l.get() | 145 l = l.get() |
141 for i := range l.zone { | 146 for i := range l.zone { |
142 zone := &l.zone[i] | 147 zone := &l.zone[i] |
143 if zone.name == name { | 148 if zone.name == name { |
144 return zone.offset, zone.isDST, true | 149 return zone.offset, zone.isDST, true |
145 } | 150 } |
146 } | 151 } |
147 return | 152 return |
148 } | 153 } |
149 | 154 |
150 // LookupOffset returns information about the time zone with | 155 // lookupOffset returns information about the time zone with |
151 // the given offset (such as -5*60*60). | 156 // the given offset (such as -5*60*60). |
152 func (l *Location) LookupOffset(offset int) (name string, isDST bool, ok bool) { | 157 func (l *Location) lookupOffset(offset int) (name string, isDST bool, ok bool) { |
153 l = l.get() | 158 l = l.get() |
154 for i := range l.zone { | 159 for i := range l.zone { |
155 zone := &l.zone[i] | 160 zone := &l.zone[i] |
156 if zone.offset == offset { | 161 if zone.offset == offset { |
157 return zone.name, zone.isDST, true | 162 return zone.name, zone.isDST, true |
158 } | 163 } |
159 } | 164 } |
160 return | 165 return |
161 } | 166 } |
162 | 167 |
163 // NOTE(rsc): Eventually we will need to accept the POSIX TZ environment | 168 // NOTE(rsc): Eventually we will need to accept the POSIX TZ environment |
164 // syntax too, but I don't feel like implementing it today. | 169 // syntax too, but I don't feel like implementing it today. |
165 | 170 |
166 // NOTE(rsc): Using the IANA names below means ensuring we have access | 171 // NOTE(rsc): Using the IANA names below means ensuring we have access |
167 // to the database. Probably we will ship the files in $GOROOT/lib/zoneinfo/ | 172 // to the database. Probably we will ship the files in $GOROOT/lib/zoneinfo/ |
168 // and only look there if there are no system files available (such as on Window
s). | 173 // and only look there if there are no system files available (such as on Window
s). |
169 // The files total 200 kB. | 174 // The files total 200 kB. |
170 | 175 |
171 // LoadLocation returns a Location describing the named location or time zone. | 176 // LoadLocation returns the Location with the given name. |
172 // | 177 // |
173 // If the name is "" or "UTC", LoadLocation returns UTC. | 178 // If the name is "" or "UTC", LoadLocation returns UTC. |
174 // If the name is "Local", LoadLocation returns Local. | 179 // If the name is "Local", LoadLocation returns Local. |
175 // | 180 // |
176 // Otherwise, the name is taken to be a location name corresponding to a file | 181 // Otherwise, the name is taken to be a location name corresponding to a file |
177 // in the IANA Time Zone database, such as "America/New_York". | 182 // in the IANA Time Zone database, such as "America/New_York". |
178 func LoadLocation(name string) (*Location, error) { | 183 func LoadLocation(name string) (*Location, error) { |
179 if name == "" || name == "UTC" { | 184 if name == "" || name == "UTC" { |
180 return UTC, nil | 185 return UTC, nil |
181 } | 186 } |
182 if name == "Local" { | 187 if name == "Local" { |
183 return Local, nil | 188 return Local, nil |
184 } | 189 } |
185 return loadLocation(name) | 190 return loadLocation(name) |
186 } | 191 } |
LEFT | RIGHT |