github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/time/zoneinfo_plan9.go (about)

     1  // Copyright 2011 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  // Parse Plan 9 timezone(2) files.
     6  
     7  package time
     8  
     9  import (
    10  	"runtime"
    11  	"syscall"
    12  )
    13  
    14  func isSpace(r rune) bool {
    15  	return r == ' ' || r == '\t' || r == '\n'
    16  }
    17  
    18  // Copied from strings to avoid a dependency.
    19  func fields(s string) []string {
    20  	// First count the fields.
    21  	n := 0
    22  	inField := false
    23  	for _, rune := range s {
    24  		wasInField := inField
    25  		inField = !isSpace(rune)
    26  		if inField && !wasInField {
    27  			n++
    28  		}
    29  	}
    30  
    31  	// Now create them.
    32  	a := make([]string, n)
    33  	na := 0
    34  	fieldStart := -1 // Set to -1 when looking for start of field.
    35  	for i, rune := range s {
    36  		if isSpace(rune) {
    37  			if fieldStart >= 0 {
    38  				a[na] = s[fieldStart:i]
    39  				na++
    40  				fieldStart = -1
    41  			}
    42  		} else if fieldStart == -1 {
    43  			fieldStart = i
    44  		}
    45  	}
    46  	if fieldStart >= 0 { // Last field might end at EOF.
    47  		a[na] = s[fieldStart:]
    48  	}
    49  	return a
    50  }
    51  
    52  func loadZoneDataPlan9(s string) (l *Location, err error) {
    53  	f := fields(s)
    54  	if len(f) < 4 {
    55  		if len(f) == 2 && f[0] == "GMT" {
    56  			return UTC, nil
    57  		}
    58  		return nil, badData
    59  	}
    60  
    61  	var zones [2]zone
    62  
    63  	// standard timezone offset
    64  	o, err := atoi(f[1])
    65  	if err != nil {
    66  		return nil, badData
    67  	}
    68  	zones[0] = zone{name: f[0], offset: o, isDST: false}
    69  
    70  	// alternate timezone offset
    71  	o, err = atoi(f[3])
    72  	if err != nil {
    73  		return nil, badData
    74  	}
    75  	zones[1] = zone{name: f[2], offset: o, isDST: true}
    76  
    77  	// transition time pairs
    78  	var tx []zoneTrans
    79  	f = f[4:]
    80  	for i := 0; i < len(f); i++ {
    81  		zi := 0
    82  		if i%2 == 0 {
    83  			zi = 1
    84  		}
    85  		t, err := atoi(f[i])
    86  		if err != nil {
    87  			return nil, badData
    88  		}
    89  		t -= zones[0].offset
    90  		tx = append(tx, zoneTrans{when: int64(t), index: uint8(zi)})
    91  	}
    92  
    93  	// Committed to succeed.
    94  	l = &Location{zone: zones[:], tx: tx}
    95  
    96  	// Fill in the cache with information about right now,
    97  	// since that will be the most common lookup.
    98  	sec, _, _ := now()
    99  	for i := range tx {
   100  		if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
   101  			l.cacheStart = tx[i].when
   102  			l.cacheEnd = omega
   103  			if i+1 < len(tx) {
   104  				l.cacheEnd = tx[i+1].when
   105  			}
   106  			l.cacheZone = &l.zone[tx[i].index]
   107  		}
   108  	}
   109  
   110  	return l, nil
   111  }
   112  
   113  func loadZoneFilePlan9(name string) (*Location, error) {
   114  	b, err := readFile(name)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	return loadZoneDataPlan9(string(b))
   119  }
   120  
   121  func initTestingZone() {
   122  	z, err := loadLocation("America/Los_Angeles")
   123  	if err != nil {
   124  		panic("cannot load America/Los_Angeles for testing: " + err.Error())
   125  	}
   126  	z.name = "Local"
   127  	localLoc = *z
   128  }
   129  
   130  func initLocal() {
   131  	t, ok := syscall.Getenv("timezone")
   132  	if ok {
   133  		if z, err := loadZoneDataPlan9(t); err == nil {
   134  			localLoc = *z
   135  			return
   136  		}
   137  	} else {
   138  		if z, err := loadZoneFilePlan9("/adm/timezone/local"); err == nil {
   139  			localLoc = *z
   140  			localLoc.name = "Local"
   141  			return
   142  		}
   143  	}
   144  
   145  	// Fall back to UTC.
   146  	localLoc.name = "UTC"
   147  }
   148  
   149  func loadLocation(name string) (*Location, error) {
   150  	z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  	z.name = name
   155  	return z, nil
   156  }
   157  
   158  func forceZipFileForTesting(zipOnly bool) {
   159  	// We only use the zip file anyway.
   160  }