...
Run Format

Source file src/time/zoneinfo_plan9.go

Documentation: time

  // Copyright 2011 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  // Parse Plan 9 timezone(2) files.
  
  package time
  
  import (
  	"runtime"
  	"syscall"
  )
  
  func isSpace(r rune) bool {
  	return r == ' ' || r == '\t' || r == '\n'
  }
  
  // Copied from strings to avoid a dependency.
  func fields(s string) []string {
  	// First count the fields.
  	n := 0
  	inField := false
  	for _, rune := range s {
  		wasInField := inField
  		inField = !isSpace(rune)
  		if inField && !wasInField {
  			n++
  		}
  	}
  
  	// Now create them.
  	a := make([]string, n)
  	na := 0
  	fieldStart := -1 // Set to -1 when looking for start of field.
  	for i, rune := range s {
  		if isSpace(rune) {
  			if fieldStart >= 0 {
  				a[na] = s[fieldStart:i]
  				na++
  				fieldStart = -1
  			}
  		} else if fieldStart == -1 {
  			fieldStart = i
  		}
  	}
  	if fieldStart >= 0 { // Last field might end at EOF.
  		a[na] = s[fieldStart:]
  	}
  	return a
  }
  
  func loadZoneDataPlan9(s string) (l *Location, err error) {
  	f := fields(s)
  	if len(f) < 4 {
  		if len(f) == 2 && f[0] == "GMT" {
  			return UTC, nil
  		}
  		return nil, badData
  	}
  
  	var zones [2]zone
  
  	// standard timezone offset
  	o, err := atoi(f[1])
  	if err != nil {
  		return nil, badData
  	}
  	zones[0] = zone{name: f[0], offset: o, isDST: false}
  
  	// alternate timezone offset
  	o, err = atoi(f[3])
  	if err != nil {
  		return nil, badData
  	}
  	zones[1] = zone{name: f[2], offset: o, isDST: true}
  
  	// transition time pairs
  	var tx []zoneTrans
  	f = f[4:]
  	for i := 0; i < len(f); i++ {
  		zi := 0
  		if i%2 == 0 {
  			zi = 1
  		}
  		t, err := atoi(f[i])
  		if err != nil {
  			return nil, badData
  		}
  		t -= zones[0].offset
  		tx = append(tx, zoneTrans{when: int64(t), index: uint8(zi)})
  	}
  
  	// Committed to succeed.
  	l = &Location{zone: zones[:], tx: tx}
  
  	// Fill in the cache with information about right now,
  	// since that will be the most common lookup.
  	sec, _, _ := now()
  	for i := range tx {
  		if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
  			l.cacheStart = tx[i].when
  			l.cacheEnd = omega
  			if i+1 < len(tx) {
  				l.cacheEnd = tx[i+1].when
  			}
  			l.cacheZone = &l.zone[tx[i].index]
  		}
  	}
  
  	return l, nil
  }
  
  func loadZoneFilePlan9(name string) (*Location, error) {
  	b, err := readFile(name)
  	if err != nil {
  		return nil, err
  	}
  	return loadZoneDataPlan9(string(b))
  }
  
  func initTestingZone() {
  	z, err := loadLocation("America/Los_Angeles")
  	if err != nil {
  		panic("cannot load America/Los_Angeles for testing: " + err.Error())
  	}
  	z.name = "Local"
  	localLoc = *z
  }
  
  func initLocal() {
  	t, ok := syscall.Getenv("timezone")
  	if ok {
  		if z, err := loadZoneDataPlan9(t); err == nil {
  			localLoc = *z
  			return
  		}
  	} else {
  		if z, err := loadZoneFilePlan9("/adm/timezone/local"); err == nil {
  			localLoc = *z
  			localLoc.name = "Local"
  			return
  		}
  	}
  
  	// Fall back to UTC.
  	localLoc.name = "UTC"
  }
  
  func loadLocation(name string) (*Location, error) {
  	z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name)
  	if err != nil {
  		return nil, err
  	}
  	z.name = name
  	return z, nil
  }
  
  func forceZipFileForTesting(zipOnly bool) {
  	// We only use the zip file anyway.
  }
  

View as plain text