-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Summary
TimeSpan
exposes several From*
methods that allow users to create a timespan using a double
. However, double
is a binary based floating-point format and thus has natural imprecision that can introduce error. For example, TimeSpan.FromSeconds(101.832)
is not 101 seconds, 832 milliseconds
, but rather is 101 seconds, 831.9999999999936335370875895023345947265625 milliseconds
.
This has, over time, led to repeated user confusion and bugs in the API surface that users have had to rationalize and deal with. It is also one of the less efficient ways to represent this data and makes it problematic for users wanting or expecting a particular behavior
As such, it is proposed that new overloads be provided, allowing users to pass in integers so they can get the desired and intended behavior. It may be worth considering whether or not the double
overloads should be "deprecated" (either via obsoletion or some analyzer) to help direct users towards success.
API Proposal
namespace System;
public partial struct TimeSpan
{
public static TimeSpan FromDays(int days, int hours = 0, int minutes = 0, int seconds = 0, int milliseconds = 0, int microseconds = 0);
public static TimeSpan FromHours(int hours, int minutes = 0, int seconds = 0, int milliseconds = 0, int microseconds = 0);
public static TimeSpan FromMinutes(int minutes, int seconds = 0, int milliseconds = 0, int microseconds = 0);
public static TimeSpan FromSeconds(int seconds, int milliseconds = 0, int microseconds = 0);
public static TimeSpan FromMilliseconds(int milliseconds, int microseconds = 0);
public static TimeSpan FromMicroseconds(int microseconds);
}
Additional Considerations
It may be desirable to not use default parameters. However, this provides a benefit that a user can do something like FromDays(5, seconds: 30)
if that were appropriate for their use case.
After these APIs are exposed, calling From(x)
where x
was an integer may produce a different result in various edge cases.
APIs where the user specifies a uint
, long
, or ulong
would still end up calling the double
overload due to the implicit conversion that exists in C#. Thus, an analyzer or deprecation of the double
overloads may be desirable to help users achieve success.
Exposing overloads that take decimal
could also be desirable and would avoid the issues around precision loss, but would be much less performant than breaking it apart like this.