-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
time.Duration
is currently very prone to accidental misuse, especially when interoperating with libraries and/or wire formats external to Go (c.f. http://golang.org/issue/20678).
Some common errors include:
- Unchecked conversions from floating-point seconds.
- Unchecked overflow when multiplying
time.Duration
values. - Conversion from floating-point to
time.Duration
before scaling instead of after. - Accidentally scaling an already-scaled value during conversion.
https://play.golang.org/p/BwwVO5DxTj illustrates some of these issues. The bugs are unsurprising once detected, but subtle to casual readers of the code — and all of the errors currently produce unexpected values silently. (Some but not all of them would be caught by #19624.)
For Go 2, I believe we should revisit the Duration
part of the time
API.
A quick survey of other languages shows that Go's Duration
type is unusually unsafe. Among modern languages, only Swift appears to be prone to the same bugs as Go.
Out-of-range conversion and overflow
Exceptions:
- The Rust constructor panics on out-of-range conversions and provides
checked
variants of arithmetic operations. - C# raises
OverflowException
orArgumentException
for out-of-range arguments (to FromMilliseconds and friends). - Java doesn't appear to have an explicit conversion operator, but raises
ArithmeticException
on overflow to its arithmetic methods. - Python's
timedelta
raisesOverflowError
. - Standard ML raises the
Time
exception if the argument is out of range.
Floating-point or arbitrary-precision representations:
- C++11 allows the use of floating-point representations; I would expect that overflow with integer representations is undefined.
- The only OCaml time package I could find uses a floating-point representation.
- The Haskell constructor takes an arbitrary-precision
Integer
argument, but it does not appear to check ranges on floating-point to integer conversions.
Double-scaling
- Rust, Java, Python, C++11, and OCaml all have asymmetric scaling or multiplication operations: you can scale a duration by a float or an integer, but you cannot scale a duration by a duration.
- The Haskell type system will reject attempts at double-conversion: converting an
Integer
to aTimeInterval
is an explicit function call, not just a reinterpretation of the type. However, it won't stop you from erroneously multiplying aTimeInterval
by aTimeInterval
. - C# and Standard ML do not support multiplying time intervals at all, requiring a round-trip conversion through a primitive number type in user code.