Commit a76c8b24 authored by Russ Cox's avatar Russ Cox

time: make Format 2.7x faster

benchmark             old ns/op    new ns/op    delta
BenchmarkFormat            2495          937  -62.44%
BenchmarkFormatNow         2308          889  -61.48%

Update #3679.

R=r
CC=golang-dev
https://golang.org/cl/6278047
parent eb4138f4
This diff is collapsed.
......@@ -257,6 +257,30 @@ func (t Time) abs() uint64 {
return uint64(sec + (unixToInternal + internalToAbsolute))
}
// locabs is a combination of the Zone and abs methods,
// extracting both return values from a single zone lookup.
func (t Time) locabs() (name string, offset int, abs uint64) {
l := t.loc
if l == nil {
l = &utcLoc
}
// Avoid function call if we hit the local time cache.
sec := t.sec + internalToUnix
if l != &utcLoc {
if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd {
name = l.cacheZone.name
offset = l.cacheZone.offset
} else {
name, offset, _, _, _ = l.lookup(sec)
}
sec += int64(offset)
} else {
name = "UTC"
}
abs = uint64(sec + (unixToInternal + internalToAbsolute))
return
}
// Date returns the year, month, and day in which t occurs.
func (t Time) Date() (year int, month Month, day int) {
year, month, day, _ = t.date(true)
......@@ -283,8 +307,13 @@ func (t Time) Day() int {
// Weekday returns the day of the week specified by t.
func (t Time) Weekday() Weekday {
return absWeekday(t.abs())
}
// absWeekday is like Weekday but operates on an absolute time.
func absWeekday(abs uint64) Weekday {
// January 1 of the absolute year, like January 1 of 2001, was a Monday.
sec := (t.abs() + uint64(Monday)*secondsPerDay) % secondsPerWeek
sec := (abs + uint64(Monday)*secondsPerDay) % secondsPerWeek
return Weekday(int(sec) / secondsPerDay)
}
......@@ -349,7 +378,12 @@ func (t Time) ISOWeek() (year, week int) {
// Clock returns the hour, minute, and second within the day specified by t.
func (t Time) Clock() (hour, min, sec int) {
sec = int(t.abs() % secondsPerDay)
return absClock(t.abs())
}
// absClock is like clock but operates on an absolute time.
func absClock(abs uint64) (hour, min, sec int) {
sec = int(abs % secondsPerDay)
hour = sec / secondsPerHour
sec -= hour * secondsPerHour
min = sec / secondsPerMinute
......@@ -610,8 +644,13 @@ const (
// date computes the year and, only when full=true,
// the month and day in which t occurs.
func (t Time) date(full bool) (year int, month Month, day int, yday int) {
return absDate(t.abs(), full)
}
// absDate is like date but operates on an absolute time.
func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) {
// Split into time and day.
d := t.abs() / secondsPerDay
d := abs / secondsPerDay
// Account for 400 year cycles.
n := d / daysPer400Years
......
......@@ -935,9 +935,18 @@ func BenchmarkNow(b *testing.B) {
}
func BenchmarkFormat(b *testing.B) {
time := Unix(1265346057, 0)
t := Unix(1265346057, 0)
for i := 0; i < b.N; i++ {
time.Format("Mon Jan 2 15:04:05 2006")
t.Format("Mon Jan 2 15:04:05 2006")
}
}
func BenchmarkFormatNow(b *testing.B) {
// Like BenchmarkFormat, but easier, because the time zone
// lookup cache is optimized for the present.
t := Now()
for i := 0; i < b.N; i++ {
t.Format("Mon Jan 2 15:04:05 2006")
}
}
......
......@@ -123,21 +123,23 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start
// Not using sort.Search to avoid dependencies.
tx := l.tx
end = 1<<63 - 1
for len(tx) > 1 {
m := len(tx) / 2
lo := 0
hi := len(tx)
for hi-lo > 1 {
m := lo + (hi-lo)/2
lim := tx[m].when
if sec < lim {
end = lim
tx = tx[0:m]
hi = m
} else {
tx = tx[m:]
lo = m
}
}
zone := &l.zone[tx[0].index]
zone := &l.zone[tx[lo].index]
name = zone.name
offset = zone.offset
isDST = zone.isDST
start = tx[0].when
start = tx[lo].when
// end = maintained during the search
return
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment