summaryrefslogtreecommitdiff
path: root/libgo/go/time
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-12-12 23:40:51 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-12-12 23:40:51 +0000
commit46bc1fe2f5a3c7ee4273b99d700fecf1555f64e0 (patch)
tree0c68629fac9d7c6f103b401c9063ef00ed259f06 /libgo/go/time
parentdc15d51eb56c0efe84bf82b02ac2ba9a231ce69b (diff)
downloadgcc-46bc1fe2f5a3c7ee4273b99d700fecf1555f64e0.tar.gz
libgo: Update to weekly.2011-11-18.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@182266 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/time')
-rw-r--r--libgo/go/time/sleep.go194
-rw-r--r--libgo/go/time/sleep_test.go19
-rw-r--r--libgo/go/time/sys.go23
-rw-r--r--libgo/go/time/sys_plan9.go13
-rw-r--r--libgo/go/time/sys_unix.go8
-rw-r--r--libgo/go/time/sys_windows.go13
-rw-r--r--libgo/go/time/tick.go182
-rw-r--r--libgo/go/time/time.go60
-rw-r--r--libgo/go/time/time_test.go62
-rw-r--r--libgo/go/time/zoneinfo_unix.go12
-rw-r--r--libgo/go/time/zoneinfo_windows.go2
11 files changed, 233 insertions, 355 deletions
diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go
index 314622d0dc9..967fca09b99 100644
--- a/libgo/go/time/sleep.go
+++ b/libgo/go/time/sleep.go
@@ -4,54 +4,60 @@
package time
-import (
- "container/heap"
- "sync"
-)
+// Interface to timers implemented in package runtime.
+// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
+type runtimeTimer struct {
+ i int32
+ when int64
+ period int64
+ f func(int64, interface{})
+ arg interface{}
+}
+
+func startTimer(*runtimeTimer)
+func stopTimer(*runtimeTimer) bool
// The Timer type represents a single event.
-// When the Timer expires, the current time will be sent on C
-// unless the Timer represents an AfterFunc event.
+// When the Timer expires, the current time will be sent on C,
+// unless the Timer was created by AfterFunc.
type Timer struct {
C <-chan int64
- t int64 // The absolute time that the event should fire.
- f func(int64) // The function to call when the event fires.
- i int // The event's index inside eventHeap.
+ r runtimeTimer
}
-type timerHeap []*Timer
-
-// forever is the absolute time (in ns) of an event that is forever away.
-const forever = 1 << 62
-
-// maxSleepTime is the maximum length of time that a sleeper
-// sleeps for before checking if it is defunct.
-const maxSleepTime = 1e9
-
-var (
- // timerMutex guards the variables inside this var group.
- timerMutex sync.Mutex
-
- // timers holds a binary heap of pending events, terminated with a sentinel.
- timers timerHeap
-
- // currentSleeper is an ever-incrementing counter which represents
- // the current sleeper. It allows older sleepers to detect that they are
- // defunct and exit.
- currentSleeper int64
-)
-
-func init() {
- timers.Push(&Timer{t: forever}) // sentinel
+// Stop prevents the Timer from firing.
+// It returns true if the call stops the timer, false if the timer has already
+// expired or stopped.
+func (t *Timer) Stop() (ok bool) {
+ return stopTimer(&t.r)
}
// NewTimer creates a new Timer that will send
// the current time on its channel after at least ns nanoseconds.
func NewTimer(ns int64) *Timer {
c := make(chan int64, 1)
- e := after(ns, func(t int64) { c <- t })
- e.C = c
- return e
+ t := &Timer{
+ C: c,
+ r: runtimeTimer{
+ when: Nanoseconds() + ns,
+ f: sendTime,
+ arg: c,
+ },
+ }
+ startTimer(&t.r)
+ return t
+}
+
+func sendTime(now int64, c interface{}) {
+ // Non-blocking send of time on c.
+ // Used in NewTimer, it cannot block anyway (buffer).
+ // Used in NewTicker, dropping sends on the floor is
+ // the desired behavior when the reader gets behind,
+ // because the sends are periodic.
+ select {
+ case c.(chan int64) <- now:
+ default:
+ }
}
// After waits at least ns nanoseconds before sending the current time
@@ -65,113 +71,17 @@ func After(ns int64) <-chan int64 {
// in its own goroutine. It returns a Timer that can
// be used to cancel the call using its Stop method.
func AfterFunc(ns int64, f func()) *Timer {
- return after(ns, func(_ int64) {
- go f()
- })
-}
-
-// Stop prevents the Timer from firing.
-// It returns true if the call stops the timer, false if the timer has already
-// expired or stopped.
-func (e *Timer) Stop() (ok bool) {
- timerMutex.Lock()
- // Avoid removing the first event in the queue so that
- // we don't start a new sleeper unnecessarily.
- if e.i > 0 {
- heap.Remove(timers, e.i)
- }
- ok = e.f != nil
- e.f = nil
- timerMutex.Unlock()
- return
-}
-
-// after is the implementation of After and AfterFunc.
-// When the current time is after ns, it calls f with the current time.
-// It assumes that f will not block.
-func after(ns int64, f func(int64)) (e *Timer) {
- now := Nanoseconds()
- t := now + ns
- if ns > 0 && t < now {
- panic("time: time overflow")
- }
- timerMutex.Lock()
- t0 := timers[0].t
- e = &Timer{nil, t, f, -1}
- heap.Push(timers, e)
- // Start a new sleeper if the new event is before
- // the first event in the queue. If the length of time
- // until the new event is at least maxSleepTime,
- // then we're guaranteed that the sleeper will wake up
- // in time to service it, so no new sleeper is needed.
- if t0 > t && (t0 == forever || ns < maxSleepTime) {
- currentSleeper++
- go sleeper(currentSleeper)
- }
- timerMutex.Unlock()
- return
-}
-
-// sleeper continually looks at the earliest event in the queue, waits until it happens,
-// then removes any events in the queue that are due. It stops when the queue
-// is empty or when another sleeper has been started.
-func sleeper(sleeperId int64) {
- timerMutex.Lock()
- e := timers[0]
- t := Nanoseconds()
- for e.t != forever {
- if dt := e.t - t; dt > 0 {
- if dt > maxSleepTime {
- dt = maxSleepTime
- }
- timerMutex.Unlock()
- sysSleep(dt)
- timerMutex.Lock()
- if currentSleeper != sleeperId {
- // Another sleeper has been started, making this one redundant.
- break
- }
- }
- e = timers[0]
- t = Nanoseconds()
- for t >= e.t {
- if e.f != nil {
- e.f(t)
- e.f = nil
- }
- heap.Pop(timers)
- e = timers[0]
- }
+ t := &Timer{
+ r: runtimeTimer{
+ when: Nanoseconds() + ns,
+ f: goFunc,
+ arg: f,
+ },
}
- timerMutex.Unlock()
-}
-
-func (timerHeap) Len() int {
- return len(timers)
-}
-
-func (timerHeap) Less(i, j int) bool {
- return timers[i].t < timers[j].t
-}
-
-func (timerHeap) Swap(i, j int) {
- timers[i], timers[j] = timers[j], timers[i]
- timers[i].i = i
- timers[j].i = j
-}
-
-func (timerHeap) Push(x interface{}) {
- e := x.(*Timer)
- e.i = len(timers)
- timers = append(timers, e)
+ startTimer(&t.r)
+ return t
}
-func (timerHeap) Pop() interface{} {
- // TODO: possibly shrink array.
- n := len(timers) - 1
- e := timers[n]
- timers[n] = nil
- timers = timers[0:n]
- e.i = -1
- return e
+func goFunc(now int64, arg interface{}) {
+ go arg.(func())()
}
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
index 0662e3359cf..9171da3af1c 100644
--- a/libgo/go/time/sleep_test.go
+++ b/libgo/go/time/sleep_test.go
@@ -7,7 +7,9 @@ package time_test
import (
"errors"
"fmt"
+ "runtime"
"sort"
+ "sync/atomic"
"testing"
. "time"
)
@@ -47,6 +49,23 @@ func TestAfterFunc(t *testing.T) {
<-c
}
+func TestAfterStress(t *testing.T) {
+ stop := uint32(0)
+ go func() {
+ for atomic.LoadUint32(&stop) == 0 {
+ runtime.GC()
+ // Need to yield, because otherwise
+ // the main goroutine will never set the stop flag.
+ runtime.Gosched()
+ }
+ }()
+ c := Tick(1)
+ for i := 0; i < 100; i++ {
+ <-c
+ }
+ atomic.StoreUint32(&stop, 1)
+}
+
func BenchmarkAfterFunc(b *testing.B) {
i := b.N
c := make(chan bool)
diff --git a/libgo/go/time/sys.go b/libgo/go/time/sys.go
index ca1d334a5b7..a5e529b814a 100644
--- a/libgo/go/time/sys.go
+++ b/libgo/go/time/sys.go
@@ -17,25 +17,4 @@ func Seconds() int64 {
func Nanoseconds() int64
// Sleep pauses the current goroutine for at least ns nanoseconds.
-// Higher resolution sleeping may be provided by syscall.Nanosleep
-// on some operating systems.
-func Sleep(ns int64) error {
- _, err := sleep(Nanoseconds(), ns)
- return err
-}
-
-// sleep takes the current time and a duration,
-// pauses for at least ns nanoseconds, and
-// returns the current time and an error.
-func sleep(t, ns int64) (int64, error) {
- // TODO(cw): use monotonic-time once it's available
- end := t + ns
- for t < end {
- err := sysSleep(end - t)
- if err != nil {
- return 0, err
- }
- t = Nanoseconds()
- }
- return t, nil
-}
+func Sleep(ns int64)
diff --git a/libgo/go/time/sys_plan9.go b/libgo/go/time/sys_plan9.go
index a630b3ee030..e58fb519ea3 100644
--- a/libgo/go/time/sys_plan9.go
+++ b/libgo/go/time/sys_plan9.go
@@ -4,19 +4,6 @@
package time
-import (
- "os"
- "syscall"
-)
-
-func sysSleep(t int64) error {
- err := syscall.Sleep(t)
- if err != nil {
- return os.NewSyscallError("sleep", err)
- }
- return nil
-}
-
// for testing: whatever interrupts a sleep
func interrupt() {
// cannot predict pid, don't want to kill group
diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go
index 17a6a2d63e0..3d313228b01 100644
--- a/libgo/go/time/sys_unix.go
+++ b/libgo/go/time/sys_unix.go
@@ -11,14 +11,6 @@ import (
"syscall"
)
-func sysSleep(t int64) error {
- errno := syscall.Sleep(t)
- if errno != 0 && errno != syscall.EINTR {
- return os.NewSyscallError("sleep", errno)
- }
- return nil
-}
-
// for testing: whatever interrupts a sleep
func interrupt() {
syscall.Kill(os.Getpid(), syscall.SIGCHLD)
diff --git a/libgo/go/time/sys_windows.go b/libgo/go/time/sys_windows.go
index f9d6e89281c..8c7242f4275 100644
--- a/libgo/go/time/sys_windows.go
+++ b/libgo/go/time/sys_windows.go
@@ -4,19 +4,6 @@
package time
-import (
- "os"
- "syscall"
-)
-
-func sysSleep(t int64) error {
- errno := syscall.Sleep(t)
- if errno != 0 && errno != syscall.EINTR {
- return os.NewSyscallError("sleep", errno)
- }
- return nil
-}
-
// for testing: whatever interrupts a sleep
func interrupt() {
}
diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go
index 92f9eb893e4..95941a1e819 100644
--- a/libgo/go/time/tick.go
+++ b/libgo/go/time/tick.go
@@ -4,156 +4,15 @@
package time
-import (
- "errors"
- "sync"
-)
+import "errors"
// A Ticker holds a synchronous channel that delivers `ticks' of a clock
// at intervals.
type Ticker struct {
- C <-chan int64 // The channel on which the ticks are delivered.
- c chan<- int64 // The same channel, but the end we use.
- ns int64
- shutdown chan bool // Buffered channel used to signal shutdown.
- nextTick int64
- next *Ticker
+ C <-chan int64 // The channel on which the ticks are delivered.
+ r runtimeTimer
}
-// Stop turns off a ticker. After Stop, no more ticks will be sent.
-func (t *Ticker) Stop() {
- select {
- case t.shutdown <- true:
- // ok
- default:
- // Stop in progress already
- }
-}
-
-// Tick is a convenience wrapper for NewTicker providing access to the ticking
-// channel only. Useful for clients that have no need to shut down the ticker.
-func Tick(ns int64) <-chan int64 {
- if ns <= 0 {
- return nil
- }
- return NewTicker(ns).C
-}
-
-type alarmer struct {
- wakeUp chan bool // wakeup signals sent/received here
- wakeMeAt chan int64
- wakeTime int64
-}
-
-// Set alarm to go off at time ns, if not already set earlier.
-func (a *alarmer) set(ns int64) {
- switch {
- case a.wakeTime > ns:
- // Next tick we expect is too late; shut down the late runner
- // and (after fallthrough) start a new wakeLoop.
- close(a.wakeMeAt)
- fallthrough
- case a.wakeMeAt == nil:
- // There's no wakeLoop, start one.
- a.wakeMeAt = make(chan int64)
- a.wakeUp = make(chan bool, 1)
- go wakeLoop(a.wakeMeAt, a.wakeUp)
- fallthrough
- case a.wakeTime == 0:
- // Nobody else is waiting; it's just us.
- a.wakeTime = ns
- a.wakeMeAt <- ns
- default:
- // There's already someone scheduled.
- }
-}
-
-// Channel to notify tickerLoop of new Tickers being created.
-var newTicker chan *Ticker
-
-func startTickerLoop() {
- newTicker = make(chan *Ticker)
- go tickerLoop()
-}
-
-// wakeLoop delivers ticks at scheduled times, sleeping until the right moment.
-// If another, earlier Ticker is created while it sleeps, tickerLoop() will start a new
-// wakeLoop and signal that this one is done by closing the wakeMeAt channel.
-func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) {
- for wakeAt := range wakeMeAt {
- Sleep(wakeAt - Nanoseconds())
- wakeUp <- true
- }
-}
-
-// A single tickerLoop serves all ticks to Tickers. It waits for two events:
-// either the creation of a new Ticker or a tick from the alarm,
-// signaling a time to wake up one or more Tickers.
-func tickerLoop() {
- // Represents the next alarm to be delivered.
- var alarm alarmer
- var now, wakeTime int64
- var tickers *Ticker
- for {
- select {
- case t := <-newTicker:
- // Add Ticker to list
- t.next = tickers
- tickers = t
- // Arrange for a new alarm if this one precedes the existing one.
- alarm.set(t.nextTick)
- case <-alarm.wakeUp:
- now = Nanoseconds()
- wakeTime = now + 1e15 // very long in the future
- var prev *Ticker = nil
- // Scan list of tickers, delivering updates to those
- // that need it and determining the next wake time.
- // TODO(r): list should be sorted in time order.
- for t := tickers; t != nil; t = t.next {
- select {
- case <-t.shutdown:
- // Ticker is done; remove it from list.
- if prev == nil {
- tickers = t.next
- } else {
- prev.next = t.next
- }
- continue
- default:
- }
- if t.nextTick <= now {
- if len(t.c) == 0 {
- // Only send if there's room. We must not block.
- // The channel is allocated with a one-element
- // buffer, which is sufficient: if he hasn't picked
- // up the last tick, no point in sending more.
- t.c <- now
- }
- t.nextTick += t.ns
- if t.nextTick <= now {
- // Still behind; advance in one big step.
- t.nextTick += (now - t.nextTick + t.ns) / t.ns * t.ns
- }
- }
- if t.nextTick < wakeTime {
- wakeTime = t.nextTick
- }
- prev = t
- }
- if tickers != nil {
- // Please send wakeup at earliest required time.
- // If there are no tickers, don't bother.
- alarm.wakeTime = wakeTime
- alarm.wakeMeAt <- wakeTime
- } else {
- alarm.wakeTime = 0
- }
- }
- }
-}
-
-var onceStartTickerLoop sync.Once
-
// NewTicker returns a new Ticker containing a channel that will
// send the time, in nanoseconds, every ns nanoseconds. It adjusts the
// intervals to make up for pauses in delivery of the ticks. The value of
@@ -162,16 +21,33 @@ func NewTicker(ns int64) *Ticker {
if ns <= 0 {
panic(errors.New("non-positive interval for NewTicker"))
}
- c := make(chan int64, 1) // See comment on send in tickerLoop
+ // Give the channel a 1-element time buffer.
+ // If the client falls behind while reading, we drop ticks
+ // on the floor until the client catches up.
+ c := make(chan int64, 1)
t := &Ticker{
- C: c,
- c: c,
- ns: ns,
- shutdown: make(chan bool, 1),
- nextTick: Nanoseconds() + ns,
+ C: c,
+ r: runtimeTimer{
+ when: Nanoseconds() + ns,
+ period: ns,
+ f: sendTime,
+ arg: c,
+ },
}
- onceStartTickerLoop.Do(startTickerLoop)
- // must be run in background so global Tickers can be created
- go func() { newTicker <- t }()
+ startTimer(&t.r)
return t
}
+
+// Stop turns off a ticker. After Stop, no more ticks will be sent.
+func (t *Ticker) Stop() {
+ stopTimer(&t.r)
+}
+
+// Tick is a convenience wrapper for NewTicker providing access to the ticking
+// channel only. Useful for clients that have no need to shut down the ticker.
+func Tick(ns int64) <-chan int64 {
+ if ns <= 0 {
+ return nil
+ }
+ return NewTicker(ns).C
+}
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
index 859b3167278..e11d17731b4 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -237,3 +237,63 @@ func (t *Time) Weekday() int {
}
return weekday
}
+
+// julianDayNumber returns the time's Julian Day Number
+// relative to the epoch 12:00 January 1, 4713 BC, Monday.
+func julianDayNumber(year int64, month, day int) int64 {
+ a := int64(14-month) / 12
+ y := year + 4800 - a
+ m := int64(month) + 12*a - 3
+ return int64(day) + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 - 32045
+}
+
+// startOfFirstWeek returns the julian day number of the first day
+// of the first week of the given year.
+func startOfFirstWeek(year int64) (d int64) {
+ jan01 := julianDayNumber(year, 1, 1)
+ weekday := (jan01 % 7) + 1
+ if weekday <= 4 {
+ d = jan01 - weekday + 1
+ } else {
+ d = jan01 + 8 - weekday
+ }
+ return
+}
+
+// dayOfWeek returns the weekday of the given date.
+func dayOfWeek(year int64, month, day int) int {
+ t := Time{Year: year, Month: month, Day: day}
+ return t.Weekday()
+}
+
+// ISOWeek returns the time's year and week number according to ISO 8601.
+// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to
+// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1
+// of year n+1.
+func (t *Time) ISOWeek() (year int64, week int) {
+ d := julianDayNumber(t.Year, t.Month, t.Day)
+ week1Start := startOfFirstWeek(t.Year)
+
+ if d < week1Start {
+ // Previous year, week 52 or 53
+ year = t.Year - 1
+ if dayOfWeek(t.Year-1, 1, 1) == 4 || dayOfWeek(t.Year-1, 12, 31) == 4 {
+ week = 53
+ } else {
+ week = 52
+ }
+ return
+ }
+
+ if d < startOfFirstWeek(t.Year+1) {
+ // Current year, week 01..52(,53)
+ year = t.Year
+ week = int((d-week1Start)/7 + 1)
+ return
+ }
+
+ // Next year, week 1
+ year = t.Year + 1
+ week = 1
+ return
+}
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
index 8b373a13bc2..01b8bea4aad 100644
--- a/libgo/go/time/time_test.go
+++ b/libgo/go/time/time_test.go
@@ -478,6 +478,68 @@ func TestMinutesInTimeZone(t *testing.T) {
}
}
+type ISOWeekTest struct {
+ year int64 // year
+ month, day int // month and day
+ yex int64 // expected year
+ wex int // expected week
+}
+
+var isoWeekTests = []ISOWeekTest{
+ {1981, 1, 1, 1981, 1}, {1982, 1, 1, 1981, 53}, {1983, 1, 1, 1982, 52},
+ {1984, 1, 1, 1983, 52}, {1985, 1, 1, 1985, 1}, {1986, 1, 1, 1986, 1},
+ {1987, 1, 1, 1987, 1}, {1988, 1, 1, 1987, 53}, {1989, 1, 1, 1988, 52},
+ {1990, 1, 1, 1990, 1}, {1991, 1, 1, 1991, 1}, {1992, 1, 1, 1992, 1},
+ {1993, 1, 1, 1992, 53}, {1994, 1, 1, 1993, 52}, {1995, 1, 2, 1995, 1},
+ {1996, 1, 1, 1996, 1}, {1996, 1, 7, 1996, 1}, {1996, 1, 8, 1996, 2},
+ {1997, 1, 1, 1997, 1}, {1998, 1, 1, 1998, 1}, {1999, 1, 1, 1998, 53},
+ {2000, 1, 1, 1999, 52}, {2001, 1, 1, 2001, 1}, {2002, 1, 1, 2002, 1},
+ {2003, 1, 1, 2003, 1}, {2004, 1, 1, 2004, 1}, {2005, 1, 1, 2004, 53},
+ {2006, 1, 1, 2005, 52}, {2007, 1, 1, 2007, 1}, {2008, 1, 1, 2008, 1},
+ {2009, 1, 1, 2009, 1}, {2010, 1, 1, 2009, 53}, {2010, 1, 1, 2009, 53},
+ {2011, 1, 1, 2010, 52}, {2011, 1, 2, 2010, 52}, {2011, 1, 3, 2011, 1},
+ {2011, 1, 4, 2011, 1}, {2011, 1, 5, 2011, 1}, {2011, 1, 6, 2011, 1},
+ {2011, 1, 7, 2011, 1}, {2011, 1, 8, 2011, 1}, {2011, 1, 9, 2011, 1},
+ {2011, 1, 10, 2011, 2}, {2011, 1, 11, 2011, 2}, {2011, 6, 12, 2011, 23},
+ {2011, 6, 13, 2011, 24}, {2011, 12, 25, 2011, 51}, {2011, 12, 26, 2011, 52},
+ {2011, 12, 27, 2011, 52}, {2011, 12, 28, 2011, 52}, {2011, 12, 29, 2011, 52},
+ {2011, 12, 30, 2011, 52}, {2011, 12, 31, 2011, 52}, {1995, 1, 1, 1994, 52},
+ {2012, 1, 1, 2011, 52}, {2012, 1, 2, 2012, 1}, {2012, 1, 8, 2012, 1},
+ {2012, 1, 9, 2012, 2}, {2012, 12, 23, 2012, 51}, {2012, 12, 24, 2012, 52},
+ {2012, 12, 30, 2012, 52}, {2012, 12, 31, 2013, 1}, {2013, 1, 1, 2013, 1},
+ {2013, 1, 6, 2013, 1}, {2013, 1, 7, 2013, 2}, {2013, 12, 22, 2013, 51},
+ {2013, 12, 23, 2013, 52}, {2013, 12, 29, 2013, 52}, {2013, 12, 30, 2014, 1},
+ {2014, 1, 1, 2014, 1}, {2014, 1, 5, 2014, 1}, {2014, 1, 6, 2014, 2},
+ {2015, 1, 1, 2015, 1}, {2016, 1, 1, 2015, 53}, {2017, 1, 1, 2016, 52},
+ {2018, 1, 1, 2018, 1}, {2019, 1, 1, 2019, 1}, {2020, 1, 1, 2020, 1},
+ {2021, 1, 1, 2020, 53}, {2022, 1, 1, 2021, 52}, {2023, 1, 1, 2022, 52},
+ {2024, 1, 1, 2024, 1}, {2025, 1, 1, 2025, 1}, {2026, 1, 1, 2026, 1},
+ {2027, 1, 1, 2026, 53}, {2028, 1, 1, 2027, 52}, {2029, 1, 1, 2029, 1},
+ {2030, 1, 1, 2030, 1}, {2031, 1, 1, 2031, 1}, {2032, 1, 1, 2032, 1},
+ {2033, 1, 1, 2032, 53}, {2034, 1, 1, 2033, 52}, {2035, 1, 1, 2035, 1},
+ {2036, 1, 1, 2036, 1}, {2037, 1, 1, 2037, 1}, {2038, 1, 1, 2037, 53},
+ {2039, 1, 1, 2038, 52}, {2040, 1, 1, 2039, 52},
+}
+
+func TestISOWeek(t *testing.T) {
+ // Selected dates and corner cases
+ for _, wt := range isoWeekTests {
+ dt := &Time{Year: wt.year, Month: wt.month, Day: wt.day}
+ y, w := dt.ISOWeek()
+ if w != wt.wex || y != wt.yex {
+ t.Errorf("got %d/%d; expected %d/%d for %d-%02d-%02d",
+ y, w, wt.yex, wt.wex, wt.year, wt.month, wt.day)
+ }
+ }
+
+ // The only real invariant: Jan 04 is in week 1
+ for year := int64(1950); year < 2100; year++ {
+ if y, w := (&Time{Year: year, Month: 1, Day: 4}).ISOWeek(); y != year || w != 1 {
+ t.Errorf("got %d/%d; expected %d/1 for Jan 04", y, w, year)
+ }
+ }
+}
+
func BenchmarkSeconds(b *testing.B) {
for i := 0; i < b.N; i++ {
Seconds()
diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go
index 0dc42353136..b552e589aa9 100644
--- a/libgo/go/time/zoneinfo_unix.go
+++ b/libgo/go/time/zoneinfo_unix.go
@@ -12,7 +12,7 @@
package time
import (
- "io/ioutil"
+ "bytes"
"os"
)
@@ -180,11 +180,17 @@ func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
}
func readinfofile(name string) ([]zonetime, bool) {
- buf, err := ioutil.ReadFile(name)
+ var b bytes.Buffer
+
+ f, err := os.Open(name)
if err != nil {
return nil, false
}
- return parseinfo(buf)
+ defer f.Close()
+ if _, err := b.ReadFrom(f); err != nil {
+ return nil, false
+ }
+ return parseinfo(b.Bytes())
}
func setupTestingZone() {
diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
index ba152e0882a..995fd44dc06 100644
--- a/libgo/go/time/zoneinfo_windows.go
+++ b/libgo/go/time/zoneinfo_windows.go
@@ -161,7 +161,7 @@ var onceSetupZone sync.Once
func setupZone() {
var i syscall.Timezoneinformation
- if _, e := syscall.GetTimeZoneInformation(&i); e != 0 {
+ if _, e := syscall.GetTimeZoneInformation(&i); e != nil {
initError = os.NewSyscallError("GetTimeZoneInformation", e)
return
}