Unreviewed changes
9 is the latest approved patch-set.
The change was submitted with unreviewed changes in the following files:
```
The name of the file: src/time/time.go
Insertions: 75, Deletions: 37.
@@ -463,7 +463,7 @@
// Note that f* is usually the “easy” function to write: it's the
// calendrical multiplication that inverts the more complex division.
//
-// Neri and Schneider [1] prove that when f* takes the form
+// Neri and Schneider prove that when f* takes the form
//
// f*(n) = (a n + b) / c
//
@@ -538,14 +538,13 @@
// Days from March 1 through end of year
marchThruDecember = 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31
- // The number of years we shift internal time to get absolute time.
- // Must be 0 mod 400, and dates before March 1, -absoluteYears will not
- // compute correctly, but otherwise can be changed at will.
+ // absoluteYears is the number of years we subtract from internal time to get absolute time.
+ // This value must be 0 mod 400, and it defines the “absolute zero instant”
+ // mentioned in the “Computations on Times” comment above: March 1, -absoluteYears.
+ // Dates before the absolute epoch will not compute correctly,
+ // but otherwise the value can be changed as needed.
absoluteYears = 292277022400
- // The number of days we shift internal time to get absolute time.
- absoluteDays = absoluteYears/400*daysPer400Years + marchThruDecember
-
// The year of the zero Time.
// Assumed by the unixToInternal computation below.
internalYear = 1
@@ -563,18 +562,34 @@
wallToInternal int64 = (1884*365 + 1884/4 - 1884/100 + 1884/400) * secondsPerDay
)
-type (
- absSeconds uint64
- absDays uint64
- absCentury uint64
- absCyear int
- absYday int
- absMonth int
- absLeap int
- absJanFeb int
-)
+// An absSeconds counts the number of seconds since the absolute zero instant.
+type absSeconds uint64
-// dateToAbsDays takes a standard year and returns the
+// An absDays counts the number of days since the absolute zero instant.
+type absDays uint64
+
+// An absCentury counts the number of centuries since the absolute zero instant.
+type absCentury uint64
+
+// An absCyear counts the number of years since the start of a century.
+type absCyear int
+
+// An absYday counts the number of days since the start of a year.
+// Note that absolute years start on March 1.
+type absYday int
+
+// An absMonth counts the number of months since the start of a year.
+// absMonth=0 denotes March.
+type absMonth int
+
+// An absLeap is a single bit (0 or 1) denoting whether a given year is a leap year.
+type absLeap int
+
+// An absJanFeb is a single bit (0 or 1) denoting whether a given day falls in January or February.
+// That is a special case because the absolute years start in March (unlike normal calendar years).
+type absJanFeb int
+
+// dateToAbsDays takes a standard year/month/day and returns the
// number of days from the absolute epoch to that day.
func dateToAbsDays(year int64, month Month, day int) absDays {
// See “Computations on Times” comment above.
@@ -586,17 +601,21 @@
amonth += 12 * janFeb
y := uint64(year) - uint64(janFeb) + absoluteYears
- // For amonth is in the range [3,14],
+ // For amonth is in the range [3,14], we want:
//
// ayday := (153*amonth - 457) / 5
//
- // is equivalent to
+ // (See the “Computations on Times” comment above
+ // as well as Neri and Schneider, section 7.)
+ //
+ // That is equivalent to:
//
// ayday := (979*amonth - 2919) >> 5
//
- // and the latter uses a couple fewer instructions,
- // so use that one, saving a few cycles.
- // See Neri and Schneider, section 8.3.
+ // and the latter form uses a couple fewer instructions,
+ // so use it, saving a few cycles.
+ // See Neri and Schneider, section 8.3
+ // for more about this optimization.
//
// (Note that there is no saved division, because the compiler
// implements / 5 without division in all cases.)
@@ -616,7 +635,7 @@
}
// split splits days into century, cyear, ayday.
-func (days absDays) split() (century absCentury, cyear absCyear, yday absYday) {
+func (days absDays) split() (century absCentury, cyear absCyear, ayday absYday) {
// See “Computations on Times” comment above.
d := 4*uint64(days) + 3
century = absCentury(d / 146097)
@@ -631,26 +650,30 @@
// so do that instead.
cd := uint32(d%146097) | 3
- // For cdays in the range [0,146097] (100 years),
+ // For cdays in the range [0,146097] (100 years), we want:
//
// cyear := (4 cdays + 3) / 1461
// yday := (4 cdays + 3) % 1461 / 4
//
- // is equivalent to:
+ // (See the “Computations on Times” comment above
+ // as well as Neri and Schneider, section 7.)
+ //
+ // That is equivalent to:
//
// cyear := (2939745 cdays) >> 32
// yday := (2939745 cdays) & 0xFFFFFFFF / 2939745 / 4
//
// so do that instead, saving a few cycles.
- // See Neri and Schneider, section 8.3.
+ // See Neri and Schneider, section 8.3
+ // for more about this optimization.
hi, lo := bits.Mul32(2939745, uint32(cd))
cyear = absCyear(hi)
- yday = absYday(lo / 2939745 / 4)
+ ayday = absYday(lo / 2939745 / 4)
return
}
-// split splits yday into absolute month and standard (1-based) day-in-month.
-func (yday absYday) split() (m absMonth, mday int) {
+// split splits ayday into absolute month and standard (1-based) day-in-month.
+func (ayday absYday) split() (m absMonth, mday int) {
// See “Computations on Times” comment above.
//
// For yday in the range [0,366],
@@ -665,15 +688,15 @@
//
// so do that instead, saving a few cycles.
// See Neri and Schneider, section 8.3.
- d := 2141*uint32(yday) + 197913
- return absMonth(d >> 16), 1 + int(d&0xFFFF/2141)
+ d := 2141*uint32(ayday) + 197913
+ return absMonth(d >> 16), 1 + int((d&0xFFFF)/2141)
}
-// janFeb returns 1 if the March 1-based yday is in January or February, 0 otherwise.
-func (yday absYday) janFeb() absJanFeb {
+// janFeb returns 1 if the March 1-based ayday is in January or February, 0 otherwise.
+func (ayday absYday) janFeb() absJanFeb {
// See “Computations on Times” comment above.
jf := absJanFeb(0)
- if yday >= marchThruDecember {
+ if ayday >= marchThruDecember {
jf = 1
}
return jf
@@ -725,7 +748,7 @@
return
}
-// yearYday converts days into standard year, yday.
+// yearYday converts days into the standard year and 1-based yday.
func (days absDays) yearYday() (year, yday int) {
century, cyear, ayday := days.split()
janFeb := ayday.janFeb()
@@ -894,7 +917,7 @@
// Common durations. There is no definition for units of Day or larger
// to avoid confusion across daylight savings time zone transitions.
//
-// To count the number of units in a Duration, divide:
+// To count the number of units in a [Duration], divide:
//
// second := time.Second
// fmt.Print(int64(second/time.Millisecond)) // prints 1000
@@ -1244,6 +1267,17 @@
if m >= March {
adj = -2
}
+
+ // With the -2 adjustment after February,
+ // we need to compute the running sum of:
+ // 0 31 30 31 30 31 30 31 31 30 31 30 31
+ // which is:
+ // 0 31 61 92 122 153 183 214 245 275 306 336 367
+ // This is almost exactly 367/12×(m-1) except for the
+ // occasonal off-by-one suggesting there may be an
+ // integer approximation of the form (a×m + b)/c.
+ // A brute force search over small a, b, c finds that
+ // (214×m - 211) / 7 computes the function perfectly.
return (214*int(m)-211)/7 + adj
}
@@ -1254,6 +1288,10 @@
}
return 28
}
+ // With the special case of February eliminated, the pattern is
+ // 31 30 31 30 31 30 31 31 30 31 30 31
+ // Adding m&1 produces the basic alternation;
+ // adding (m>>3)&1 inverts the alternation starting in August.
return 30 + int((m+m>>3)&1)
}
```
```
The name of the file: src/time/abs_test.go
Insertions: 10, Deletions: 0.
@@ -29,6 +29,7 @@
{"AbsDate", testAbsDate},
{"DateToAbsDays", testDateToAbsDays},
{"DaysIn", testDaysIn},
+ {"DaysBefore", testDaysBefore},
}
func testAbsDaysSplit(t testingT) {
@@ -171,3 +172,12 @@
}
}
}
+
+func testDaysBefore(t testingT) {
+ for m, want := range []int{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365} {
+ d := daysBefore(Month(m + 1))
+ if d != want {
+ t.Errorf("daysBefore(%d) = %d, want %d", m, d, want)
+ }
+ }
+}
```
```
The name of the file: src/time/time_test.go
Insertions: 8, Deletions: 8.
@@ -129,10 +129,10 @@
tm := Unix(sec, 0).UTC()
newsec := tm.Unix()
if newsec != sec {
- t.Errorf("Unix(%d).Unix() = %d", sec, newsec)
+ t.Errorf("Unix(%d, 0).Unix() = %d", sec, newsec)
}
if !same(tm, golden) {
- t.Errorf("Unix(%d): // %#v", sec, tm)
+ t.Errorf("Unix(%d, 0): // %#v", sec, tm)
t.Errorf(" want=%+v", *golden)
t.Errorf(" have=%v", tm.Format(RFC3339+" MST"))
}
@@ -146,10 +146,10 @@
tm := Unix(0, nsec).UTC()
newnsec := tm.Unix()*1e9 + int64(tm.Nanosecond())
if newnsec != nsec {
- t.Errorf("NanosecondsToUTC(%d).Nanoseconds() = %d", nsec, newnsec)
+ t.Errorf("Unix(0, %d).Nanoseconds() = %d", nsec, newnsec)
}
if !same(tm, golden) {
- t.Errorf("NanosecondsToUTC(%d):", nsec)
+ t.Errorf("Unix(0, %d):", nsec)
t.Errorf(" want=%+v", *golden)
t.Errorf(" have=%+v", tm.Format(RFC3339+" MST"))
}
@@ -163,10 +163,10 @@
tm := Unix(sec, 0)
newsec := tm.Unix()
if newsec != sec {
- t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec)
+ t.Errorf("Unix(%d, 0).Seconds() = %d", sec, newsec)
}
if !same(tm, golden) {
- t.Errorf("SecondsToLocalTime(%d):", sec)
+ t.Errorf("Unix(%d, 0):", sec)
t.Errorf(" want=%+v", *golden)
t.Errorf(" have=%+v", tm.Format(RFC3339+" MST"))
}
@@ -180,10 +180,10 @@
tm := Unix(0, nsec)
newnsec := tm.Unix()*1e9 + int64(tm.Nanosecond())
if newnsec != nsec {
- t.Errorf("NanosecondsToLocalTime(%d).Seconds() = %d", nsec, newnsec)
+ t.Errorf("Unix(0, %d).Seconds() = %d", nsec, newnsec)
}
if !same(tm, golden) {
- t.Errorf("NanosecondsToLocalTime(%d):", nsec)
+ t.Errorf("Unix(0, %d):", nsec)
t.Errorf(" want=%+v", *golden)
t.Errorf(" have=%+v", tm.Format(RFC3339+" MST"))
}
```