]> Cypherpunks repositories - gostls13.git/commitdiff
time: optimize Time.ISOWeek
authorShuo <openset.wang@gmail.com>
Sun, 1 Mar 2020 02:32:32 +0000 (02:32 +0000)
committerIan Lance Taylor <iant@golang.org>
Sun, 1 Mar 2020 02:56:31 +0000 (02:56 +0000)
name       old time/op  new time/op  delta
ISOWeek-4  57.7ns ± 5%  27.9ns ±10%  -51.54%  (p=0.000 n=48+49)

Fixes #37534

Change-Id: Ic4673ced44a4b0190018e87207743ed9500fb1e0
GitHub-Last-Rev: a376c57e83a99f8e8fde297335caa85215e7aead
GitHub-Pull-Request: golang/go#36316
Reviewed-on: https://go-review.googlesource.com/c/go/+/212837
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/time/time.go
src/time/time_test.go

index 5dc9fa68ac17a5bc5d125dc1e52d1aff190ded8c..5fa09687e9cae87c8889c72d015a505ff8513098 100644 (file)
@@ -535,58 +535,26 @@ func absWeekday(abs uint64) Weekday {
 // 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, week int) {
-       year, month, day, yday := t.date(true)
-       wday := int(t.Weekday()+6) % 7 // weekday but Monday = 0.
-       const (
-               Mon int = iota
-               Tue
-               Wed
-               Thu
-               Fri
-               Sat
-               Sun
-       )
-
-       // Calculate week as number of Mondays in year up to
-       // and including today, plus 1 because the first week is week 0.
-       // Putting the + 1 inside the numerator as a + 7 keeps the
-       // numerator from being negative, which would cause it to
-       // round incorrectly.
-       week = (yday - wday + 7) / 7
-
-       // The week number is now correct under the assumption
-       // that the first Monday of the year is in week 1.
-       // If Jan 1 is a Tuesday, Wednesday, or Thursday, the first Monday
-       // is actually in week 2.
-       jan1wday := (wday - yday + 7*53) % 7
-       if Tue <= jan1wday && jan1wday <= Thu {
-               week++
+       // According to the rule that the first calendar week of a calendar year is
+       // the week including the first Thursday of that year, and that the last one is
+       // the week immediately preceding the first calendar week of the next calendar year.
+       // See https://www.iso.org/obp/ui#iso:std:iso:8601:-1:ed-1:v1:en:term:3.1.1.23 for details.
+
+       // weeks start with Monday
+       // Monday Tuesday Wednesday Thursday Friday Saturday Sunday
+       // 1      2       3         4        5      6        7
+       // +3     +2      +1        0        -1     -2       -3
+       // the offset to Thursday
+       abs := t.abs()
+       d := Thursday - absWeekday(abs)
+       // handle Sunday
+       if d == 4 {
+               d = -3
        }
-
-       // If the week number is still 0, we're in early January but in
-       // the last week of last year.
-       if week == 0 {
-               year--
-               week = 52
-               // A year has 53 weeks when Jan 1 or Dec 31 is a Thursday,
-               // meaning Jan 1 of the next year is a Friday
-               // or it was a leap year and Jan 1 of the next year is a Saturday.
-               if jan1wday == Fri || (jan1wday == Sat && isLeap(year)) {
-                       week++
-               }
-       }
-
-       // December 29 to 31 are in week 1 of next year if
-       // they are after the last Thursday of the year and
-       // December 31 is a Monday, Tuesday, or Wednesday.
-       if month == December && day >= 29 && wday < Thu {
-               if dec31wday := (wday + 31 - day) % 7; Mon <= dec31wday && dec31wday <= Wed {
-                       year++
-                       week = 1
-               }
-       }
-
-       return
+       // find the Thursday of the calendar week
+       abs += uint64(d) * secondsPerDay
+       year, _, _, yday := absDate(abs, false)
+       return year, yday/7 + 1
 }
 
 // Clock returns the hour, minute, and second within the day specified by t.
index 2fc23c4feebc0ad4f6c6dd1028c79bb13effa9d0..ffbf92acbc23cd70fdcdbe5b6884dbc53144f119 100644 (file)
@@ -1348,6 +1348,13 @@ func BenchmarkDay(b *testing.B) {
        }
 }
 
+func BenchmarkISOWeek(b *testing.B) {
+       t := Now()
+       for i := 0; i < b.N; i++ {
+               _, _ = t.ISOWeek()
+       }
+}
+
 func TestMarshalBinaryZeroTime(t *testing.T) {
        t0 := Time{}
        enc, err := t0.MarshalBinary()