Repository navigation
Add an Int64 fast path to the TimeSpan.From* polyfills - #714
Merged
Merged
Conversation
This was referenced Oct 12, 2026
This was referenced Oct 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The multi-component
TimeSpan.From*polyfills (below net9) do all of their arithmetic indecimal, so that components which overflow anInt64on their own but cancel back into range still give the right answer, as the BCL's 128-bit accumulation does. That costs hundreds of nanoseconds for a call such asTimeSpan.FromDays(1, 2, 3, 4, 5, 6).Change
All six factories go through one helper. When every component is small enough that its own tick count is at most
long.MaxValue / 8, the (at most six) components cannot overflow anInt64between them, so the ticks are summed directly inlongand the result is necessarily in range. The per-component limits are:Anything larger takes the existing
decimalpath unchanged, which still decides whether the total overflows and throws the sameArgumentOutOfRangeException. The fast path cannot throw and cannot produce a different value: within those limits thelongsum is exact.Measurements
net48, x64, Release, 5,000,000 calls each, two rounds. No allocations before or after.
FromDays(1, 2, 3, 4, 5, 6)FromHours(1, 2, 3, 4, 5)FromMinutes(1, 2, 3, 4)FromSeconds(1, 2, 3)FromMilliseconds(1, 2)FromMicroseconds(1)FromSeconds(1e12, -1e15, 0)(decimal fallback)The fallback row is the same code as before plus the range checks, and is unchanged within the noise.
Tests
The expected value is computed in the test with exact
decimalarithmetic (nullwhen the total is outside the tick range), and every factory that can take the components is compared with it;nullmust be anArgumentOutOfRangeException, and any other exception fails the test.TimeSpan.MaxValue/MinValuetruncated to microseconds and one microsecond past them,int/longextremes in every position+/-922337203685477580microseconds is accepted and gives+/-9223372036854775800ticks, one more throws; components far out of range that cancel back into range; components that are each in range but overflow together2^n - 1,2^n,2^n + 1for everyn, around every power of ten,long.MinValue/MaxValue, and atlong.MaxValue / d / ticksPerUnitand its neighbours ford= 1..16, which covers the fast-path limits (d= 8) and the overflow limits (d= 1) from both sides, in both signsFromMicroseconds(long)on its own; below net9 alongargument binds to the BCL'sFromMicroseconds(double)on net7 and net8, so the large values are only asserted when a run-time probe shows the exact overload is in useOn net9 and later the same tests run against the BCL.