diff options
Diffstat (limited to 'libgo/go/time/zoneinfo.go')
-rw-r--r-- | libgo/go/time/zoneinfo.go | 87 |
1 files changed, 80 insertions, 7 deletions
diff --git a/libgo/go/time/zoneinfo.go b/libgo/go/time/zoneinfo.go index 1c6186258f9..c8e53a27cf0 100644 --- a/libgo/go/time/zoneinfo.go +++ b/libgo/go/time/zoneinfo.go @@ -45,6 +45,13 @@ type zoneTrans struct { isstd, isutc bool // ignored - no idea what these mean } +// alpha and omega are the beginning and end of time for zone +// transitions. +const ( + alpha = -1 << 63 // math.MinInt64 + omega = 1<<63 - 1 // math.MaxInt64 +) + // UTC represents Universal Coordinated Time (UTC). var UTC *Location = &utcLoc @@ -83,9 +90,9 @@ func FixedZone(name string, offset int) *Location { l := &Location{ name: name, zone: []zone{{name, offset, false}}, - tx: []zoneTrans{{-1 << 63, 0, false, false}}, - cacheStart: -1 << 63, - cacheEnd: 1<<63 - 1, + tx: []zoneTrans{{alpha, 0, false, false}}, + cacheStart: alpha, + cacheEnd: omega, } l.cacheZone = &l.zone[0] return l @@ -101,12 +108,12 @@ func FixedZone(name string, offset int) *Location { func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start, end int64) { l = l.get() - if len(l.tx) == 0 { + if len(l.zone) == 0 { name = "UTC" offset = 0 isDST = false - start = -1 << 63 - end = 1<<63 - 1 + start = alpha + end = omega return } @@ -119,10 +126,24 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start return } + if len(l.tx) == 0 || sec < l.tx[0].when { + zone := &l.zone[l.lookupFirstZone()] + name = zone.name + offset = zone.offset + isDST = zone.isDST + start = alpha + if len(l.tx) > 0 { + end = l.tx[0].when + } else { + end = omega + } + return + } + // Binary search for entry with largest time <= sec. // Not using sort.Search to avoid dependencies. tx := l.tx - end = 1<<63 - 1 + end = omega lo := 0 hi := len(tx) for hi-lo > 1 { @@ -144,6 +165,58 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start return } +// lookupFirstZone returns the index of the time zone to use for times +// before the first transition time, or when there are no transition +// times. +// +// The reference implementation in localtime.c from +// http://www.iana.org/time-zones/repository/releases/tzcode2013g.tar.gz +// implements the following algorithm for these cases: +// 1) If the first zone is unused by the transitions, use it. +// 2) Otherwise, if there are transition times, and the first +// transition is to a zone in daylight time, find the first +// non-daylight-time zone before and closest to the first transition +// zone. +// 3) Otherwise, use the first zone that is not daylight time, if +// there is one. +// 4) Otherwise, use the first zone. +func (l *Location) lookupFirstZone() int { + // Case 1. + if !l.firstZoneUsed() { + return 0 + } + + // Case 2. + if len(l.tx) > 0 && l.zone[l.tx[0].index].isDST { + for zi := int(l.tx[0].index) - 1; zi >= 0; zi-- { + if !l.zone[zi].isDST { + return zi + } + } + } + + // Case 3. + for zi := range l.zone { + if !l.zone[zi].isDST { + return zi + } + } + + // Case 4. + return 0 +} + +// firstZoneUsed returns whether the first zone is used by some +// transition. +func (l *Location) firstZoneUsed() bool { + for _, tx := range l.tx { + if tx.index == 0 { + return true + } + } + return false +} + // lookupName returns information about the time zone with // the given name (such as "EST") at the given pseudo-Unix time // (what the given time of day would be in UTC). |