Source file src/time/zoneinfo_plan9.go

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

View as plain text