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

View as plain text