Skip to content

Add net9 TimeSpan unit constants - #591

Merged
SimonCropp merged 1 commit into
mainfrom
timespan-constants
Sep 10, 2026
Merged

Add net9 TimeSpan unit constants#591
SimonCropp merged 1 commit into
mainfrom
timespan-constants

Conversation

@SimonCropp

Copy link
Copy Markdown
Owner

Adds the fifteen unit constants introduced in net9:

HoursPerDay 24
MicrosecondsPerDay / PerHour / PerMillisecond / PerMinute / PerSecond
MillisecondsPerDay / PerHour / PerMinute / PerSecond
MinutesPerDay / PerHour
SecondsPerDay / PerHour / PerMinute

API count 1073 to 1088.

Polyfill already had the net9 TimeSpan.From* overloads that shipped alongside these, and TimeSpanPolyfill.cs even carried five of the values as private consts to implement them, so the feature was half covered.

These are properties, not consts

In the BCL these are const fields. Extension members cannot declare constants, so they are exposed as static properties instead.

Reading them compiles identically, which covers essentially all use. What does not work is a constant expression:

const long x = TimeSpan.SecondsPerMinute;   // fine on net9+, fails to compile below

Also switch cases, attribute arguments and default parameter values. There is no way around it short of the BCL type itself, so it is recorded as a //Note: on each of the fifteen.

HoursPerDay is int and the rest are long, matching the BCL, so that assignments to int keep compiling.

Tests

Beyond asserting each value, a second test cross-checks them against the TicksPer* constants that have been in the BCL since the beginning:

await Assert.That(TimeSpan.MillisecondsPerSecond * TimeSpan.TicksPerMillisecond).IsEqualTo(TimeSpan.TicksPerSecond);
await Assert.That(TimeSpan.HoursPerDay * TimeSpan.TicksPerHour).IsEqualTo(TimeSpan.TicksPerDay);

So the numbers are verified against something independent of this change rather than only against literals I typed. Note that TicksPerMicrosecond could not be used for this, since it is itself net7 only, so the microsecond values are chained through milliseconds instead.

On net9 and above these tests read the BCL consts, and below they read the polyfilled properties, with the same assertions either way.

Verification

  • Solution builds clean in Release. Consume builds clean in Debug across all 22 target frameworks.
  • Tests green on net11.0 (1674), net462 (1640), net8.0 (1671) and net10.0 (1674), plus PublicTests, EmbeddedTests, UnsafeTests, NoRefsTests and NoExtrasTests.

Adds the fifteen unit constants introduced in net9:

    HoursPerDay
    MicrosecondsPerDay, PerHour, PerMillisecond, PerMinute, PerSecond
    MillisecondsPerDay, PerHour, PerMinute, PerSecond
    MinutesPerDay, PerHour
    SecondsPerDay, PerHour, PerMinute

Polyfill already had the net9 TimeSpan.From* overloads that shipped
alongside these, so the feature was half covered.

In the BCL these are const fields. Extension members cannot declare
constants, so they are exposed as static properties. Reading them
compiles the same way, but they cannot be used in a constant expression,
a switch case, an attribute argument or a default parameter value. That
is recorded as a note on each one.

HoursPerDay is int, the rest are long, matching the BCL.

Beyond asserting each value, the tests cross-check them against the
TicksPer* constants that have always been in the BCL, so the numbers are
verified against something independent of this change.
@SimonCropp SimonCropp added this to the 11.3.0 milestone Sep 10, 2026
@SimonCropp
SimonCropp merged commit 874900b into main Sep 10, 2026
4 of 6 checks passed
@SimonCropp
SimonCropp deleted the timespan-constants branch September 10, 2026 02:57
This was referenced Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant