Skip to content

New TimeSpan.From overloads which take integers. #93890

@tannergooding

Description

@tannergooding

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions