Merge pull request #762 from spongehah/golib/time
lib/time: patch div and Time.Round
This commit is contained in:
@@ -1072,3 +1072,114 @@ func norm(hi, lo, base int) (nhi, nlo int) {
|
|||||||
}
|
}
|
||||||
return hi, lo
|
return hi, lo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Round returns the result of rounding t to the nearest multiple of d (since the zero time).
|
||||||
|
// The rounding behavior for halfway values is to round up.
|
||||||
|
// If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged.
|
||||||
|
//
|
||||||
|
// Round operates on the time as an absolute duration since the
|
||||||
|
// zero time; it does not operate on the presentation form of the
|
||||||
|
// time. Thus, Round(Hour) may return a time with a non-zero
|
||||||
|
// minute, depending on the time's Location.
|
||||||
|
func (t Time) Round(d Duration) Time {
|
||||||
|
t.stripMono()
|
||||||
|
if d <= 0 {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
_, r := div(t, d)
|
||||||
|
if lessThanHalf(r, d) {
|
||||||
|
return t.Add(-r)
|
||||||
|
}
|
||||||
|
return t.Add(d - r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// div divides t by d and returns the quotient parity and remainder.
|
||||||
|
// We don't use the quotient parity anymore (round half up instead of round to even)
|
||||||
|
// but it's still here in case we change our minds.
|
||||||
|
func div(t Time, d Duration) (qmod2 int, r Duration) {
|
||||||
|
neg := false
|
||||||
|
nsec := t.nsec()
|
||||||
|
sec := t.sec()
|
||||||
|
if sec < 0 {
|
||||||
|
// Operate on absolute value.
|
||||||
|
neg = true
|
||||||
|
sec = -sec
|
||||||
|
nsec = -nsec
|
||||||
|
if nsec < 0 {
|
||||||
|
nsec += 1e9
|
||||||
|
sec-- // sec >= 1 before the -- so safe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
// Special case: 2d divides 1 second.
|
||||||
|
case d < Second && Second%(d+d) == 0:
|
||||||
|
qmod2 = int(nsec/int32(d)) & 1
|
||||||
|
r = Duration(nsec % int32(d))
|
||||||
|
|
||||||
|
// Special case: d is a multiple of 1 second.
|
||||||
|
case d%Second == 0:
|
||||||
|
d1 := int64(d / Second)
|
||||||
|
qmod2 = int(sec/d1) & 1
|
||||||
|
r = Duration(sec%d1)*Second + Duration(nsec)
|
||||||
|
|
||||||
|
// General case.
|
||||||
|
// This could be faster if more cleverness were applied,
|
||||||
|
// but it's really only here to avoid special case restrictions in the API.
|
||||||
|
// No one will care about these cases.
|
||||||
|
default:
|
||||||
|
// Compute nanoseconds as 128-bit number.
|
||||||
|
sec := uint64(sec)
|
||||||
|
tmp := (sec >> 32) * 1e9
|
||||||
|
u1 := tmp >> 32
|
||||||
|
u0 := tmp << 32
|
||||||
|
tmp = (sec & 0xFFFFFFFF) * 1e9
|
||||||
|
u0x, u0 := u0, u0+tmp
|
||||||
|
if u0 < u0x {
|
||||||
|
u1++
|
||||||
|
}
|
||||||
|
u0x, u0 = u0, u0+uint64(nsec)
|
||||||
|
if u0 < u0x {
|
||||||
|
u1++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute remainder by subtracting r<<k for decreasing k.
|
||||||
|
// Quotient parity is whether we subtract on last round.
|
||||||
|
d1 := uint64(d)
|
||||||
|
for d1>>63 != 1 {
|
||||||
|
d1 <<= 1
|
||||||
|
}
|
||||||
|
d0 := uint64(0)
|
||||||
|
for {
|
||||||
|
qmod2 = 0
|
||||||
|
if u1 > d1 || u1 == d1 && u0 >= d0 {
|
||||||
|
// subtract
|
||||||
|
qmod2 = 1
|
||||||
|
u0x, u0 = u0, u0-d0
|
||||||
|
if u0 > u0x {
|
||||||
|
u1--
|
||||||
|
}
|
||||||
|
u1 -= d1
|
||||||
|
}
|
||||||
|
if d1 == 0 && d0 == uint64(d) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
d0 >>= 1
|
||||||
|
d0 |= (d1 & 1) << 63
|
||||||
|
d1 >>= 1
|
||||||
|
}
|
||||||
|
r = Duration(u0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if neg && r != 0 {
|
||||||
|
// If input was negative and not an exact multiple of d, we computed q, r such that
|
||||||
|
// q*d + r = -t
|
||||||
|
// But the right answers are given by -(q-1), d-r:
|
||||||
|
// q*d + r = -t
|
||||||
|
// -q*d - r = t
|
||||||
|
// -(q-1)*d + (d - r) = t
|
||||||
|
qmod2 ^= 1
|
||||||
|
r = d - r
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user