Problem
TimeSpan.Humanize() currently reduces duration counts to int before passing them into the formatter pipeline. That works for normal spans, but very large spans can exceed int.MaxValue when the selected output unit is seconds, milliseconds, minutes, or hours.
The current path is roughly:
TimeSpanHumanizeExtensions.GetTimeUnitNumericalValue(...) returns int
GetNormalCaseTimeAsInteger(...) casts TotalSeconds / TotalMilliseconds / etc. to int when the requested unit is the maximum unit
BuildFormatTimePart(...) then calls Math.Abs(int) before IFormatter.TimeSpanHumanize(TimeUnit, int, ...)
This can make extreme values runtime/TFM dependent. While adding coverage in PR #1727, TimeSpan.MaxValue.Humanize(maxUnit: TimeUnit.Second, minUnit: TimeUnit.Second) overflowed on some targets because the cast produced int.MinValue, and Math.Abs(int.MinValue) throws. Other targets produced a different saturated value, so the behavior was not a stable cross-target invariant.
Why this matters
Even if TimeSpan.MaxValue is an edge case, the library should avoid undefined or runtime-dependent behavior when humanizing large but valid TimeSpan values. At minimum, it should not throw because an internal cast overflowed before formatting.
Possible approaches
- Make the
TimeSpan.Humanize internal count calculation long-safe and avoid Math.Abs(int.MinValue).
- Consider whether the formatter contract should support
long counts for time spans. Today IFormatter.TimeSpanHumanize(TimeUnit, int, bool) and related formatter/profile methods are int-based, so a public API change needs careful compatibility review.
- If full
long support is too broad, define and test explicit saturating/clamping behavior for counts above int.MaxValue.
Acceptance criteria
TimeSpan.Humanize() has deterministic behavior for very large durations across supported TFMs.
- Very large valid
TimeSpan values do not fail due to an internal numeric overflow in count calculation or Math.Abs.
- Tests cover at least one count above
int.MaxValue for a small unit such as seconds or milliseconds.
- If formatter public APIs change, API approval snapshots and custom formatter compatibility are handled intentionally.
Related context: discovered while raising coverage in PR #1727.
Problem
TimeSpan.Humanize()currently reduces duration counts tointbefore passing them into the formatter pipeline. That works for normal spans, but very large spans can exceedint.MaxValuewhen the selected output unit is seconds, milliseconds, minutes, or hours.The current path is roughly:
TimeSpanHumanizeExtensions.GetTimeUnitNumericalValue(...)returnsintGetNormalCaseTimeAsInteger(...)castsTotalSeconds/TotalMilliseconds/ etc. tointwhen the requested unit is the maximum unitBuildFormatTimePart(...)then callsMath.Abs(int)beforeIFormatter.TimeSpanHumanize(TimeUnit, int, ...)This can make extreme values runtime/TFM dependent. While adding coverage in PR #1727,
TimeSpan.MaxValue.Humanize(maxUnit: TimeUnit.Second, minUnit: TimeUnit.Second)overflowed on some targets because the cast producedint.MinValue, andMath.Abs(int.MinValue)throws. Other targets produced a different saturated value, so the behavior was not a stable cross-target invariant.Why this matters
Even if
TimeSpan.MaxValueis an edge case, the library should avoid undefined or runtime-dependent behavior when humanizing large but validTimeSpanvalues. At minimum, it should not throw because an internal cast overflowed before formatting.Possible approaches
TimeSpan.Humanizeinternal count calculation long-safe and avoidMath.Abs(int.MinValue).longcounts for time spans. TodayIFormatter.TimeSpanHumanize(TimeUnit, int, bool)and related formatter/profile methods areint-based, so a public API change needs careful compatibility review.longsupport is too broad, define and test explicit saturating/clamping behavior for counts aboveint.MaxValue.Acceptance criteria
TimeSpan.Humanize()has deterministic behavior for very large durations across supported TFMs.TimeSpanvalues do not fail due to an internal numeric overflow in count calculation orMath.Abs.int.MaxValuefor a small unit such as seconds or milliseconds.Related context: discovered while raising coverage in PR #1727.