github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/time/zoneinfo_windows.go (about)

     1  // Copyright 2009 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  package time
     6  
     7  import (
     8  	"errors"
     9  	"runtime"
    10  	"syscall"
    11  )
    12  
    13  // TODO(rsc): Fall back to copy of zoneinfo files.
    14  
    15  // BUG(brainman,rsc): On Windows, the operating system does not provide complete
    16  // time zone information.
    17  // The implementation assumes that this year's rules for daylight savings
    18  // time apply to all previous and future years as well.
    19  // Also, time zone abbreviations are unavailable.  The implementation constructs
    20  // them using the capital letters from a longer time zone description.
    21  
    22  // abbrev returns the abbreviation to use for the given zone name.
    23  func abbrev(name []uint16) string {
    24  	// name is 'Pacific Standard Time' but we want 'PST'.
    25  	// Extract just capital letters.  It's not perfect but the
    26  	// information we need is not available from the kernel.
    27  	// Because time zone abbreviations are not unique,
    28  	// Windows refuses to expose them.
    29  	//
    30  	// http://social.msdn.microsoft.com/Forums/eu/vclanguage/thread/a87e1d25-fb71-4fe0-ae9c-a9578c9753eb
    31  	// http://stackoverflow.com/questions/4195948/windows-time-zone-abbreviations-in-asp-net
    32  	var short []rune
    33  	for _, c := range name {
    34  		if 'A' <= c && c <= 'Z' {
    35  			short = append(short, rune(c))
    36  		}
    37  	}
    38  	return string(short)
    39  }
    40  
    41  // pseudoUnix returns the pseudo-Unix time (seconds since Jan 1 1970 *LOCAL TIME*)
    42  // denoted by the system date+time d in the given year.
    43  // It is up to the caller to convert this local time into a UTC-based time.
    44  func pseudoUnix(year int, d *syscall.Systemtime) int64 {
    45  	// Windows specifies daylight savings information in "day in month" format:
    46  	// d.Month is month number (1-12)
    47  	// d.DayOfWeek is appropriate weekday (Sunday=0 to Saturday=6)
    48  	// d.Day is week within the month (1 to 5, where 5 is last week of the month)
    49  	// d.Hour, d.Minute and d.Second are absolute time
    50  	day := 1
    51  	t := Date(year, Month(d.Month), day, int(d.Hour), int(d.Minute), int(d.Second), 0, UTC)
    52  	i := int(d.DayOfWeek) - int(t.Weekday())
    53  	if i < 0 {
    54  		i += 7
    55  	}
    56  	day += i
    57  	if week := int(d.Day) - 1; week < 4 {
    58  		day += week * 7
    59  	} else {
    60  		// "Last" instance of the day.
    61  		day += 4 * 7
    62  		if day > daysIn(Month(d.Month), year) {
    63  			day -= 7
    64  		}
    65  	}
    66  	return t.sec + int64(day-1)*secondsPerDay + internalToUnix
    67  }
    68  
    69  func initLocalFromTZI(i *syscall.Timezoneinformation) {
    70  	l := &localLoc
    71  
    72  	nzone := 1
    73  	if i.StandardDate.Month > 0 {
    74  		nzone++
    75  	}
    76  	l.zone = make([]zone, nzone)
    77  
    78  	std := &l.zone[0]
    79  	std.name = abbrev(i.StandardName[0:])
    80  	if nzone == 1 {
    81  		// No daylight savings.
    82  		std.offset = -int(i.Bias) * 60
    83  		l.cacheStart = -1 << 63
    84  		l.cacheEnd = 1<<63 - 1
    85  		l.cacheZone = std
    86  		l.tx = make([]zoneTrans, 1)
    87  		l.tx[0].when = l.cacheStart
    88  		l.tx[0].index = 0
    89  		return
    90  	}
    91  
    92  	// StandardBias must be ignored if StandardDate is not set,
    93  	// so this computation is delayed until after the nzone==1
    94  	// return above.
    95  	std.offset = -int(i.Bias+i.StandardBias) * 60
    96  
    97  	dst := &l.zone[1]
    98  	dst.name = abbrev(i.DaylightName[0:])
    99  	dst.offset = -int(i.Bias+i.DaylightBias) * 60
   100  	dst.isDST = true
   101  
   102  	// Arrange so that d0 is first transition date, d1 second,
   103  	// i0 is index of zone after first transition, i1 second.
   104  	d0 := &i.StandardDate
   105  	d1 := &i.DaylightDate
   106  	i0 := 0
   107  	i1 := 1
   108  	if d0.Month > d1.Month {
   109  		d0, d1 = d1, d0
   110  		i0, i1 = i1, i0
   111  	}
   112  
   113  	// 2 tx per year, 100 years on each side of this year
   114  	l.tx = make([]zoneTrans, 400)
   115  
   116  	t := Now().UTC()
   117  	year := t.Year()
   118  	txi := 0
   119  	for y := year - 100; y < year+100; y++ {
   120  		tx := &l.tx[txi]
   121  		tx.when = pseudoUnix(y, d0) - int64(l.zone[i1].offset)
   122  		tx.index = uint8(i0)
   123  		txi++
   124  
   125  		tx = &l.tx[txi]
   126  		tx.when = pseudoUnix(y, d1) - int64(l.zone[i0].offset)
   127  		tx.index = uint8(i1)
   128  		txi++
   129  	}
   130  }
   131  
   132  var usPacific = syscall.Timezoneinformation{
   133  	Bias: 8 * 60,
   134  	StandardName: [32]uint16{
   135  		'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'S', 't', 'a', 'n', 'd', 'a', 'r', 'd', ' ', 'T', 'i', 'm', 'e',
   136  	},
   137  	StandardDate: syscall.Systemtime{Month: 11, Day: 1, Hour: 2},
   138  	DaylightName: [32]uint16{
   139  		'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'D', 'a', 'y', 'l', 'i', 'g', 'h', 't', ' ', 'T', 'i', 'm', 'e',
   140  	},
   141  	DaylightDate: syscall.Systemtime{Month: 3, Day: 2, Hour: 2},
   142  	DaylightBias: -60,
   143  }
   144  
   145  func initTestingZone() {
   146  	initLocalFromTZI(&usPacific)
   147  }
   148  
   149  func initLocal() {
   150  	var i syscall.Timezoneinformation
   151  	if _, err := syscall.GetTimeZoneInformation(&i); err != nil {
   152  		localLoc.name = "UTC"
   153  		return
   154  	}
   155  	initLocalFromTZI(&i)
   156  }
   157  
   158  func loadLocation(name string) (*Location, error) {
   159  	if z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name); err == nil {
   160  		z.name = name
   161  		return z, nil
   162  	}
   163  	return nil, errors.New("unknown time zone " + name)
   164  }