Last active
October 31, 2023 01:07
-
-
Save tcortega/f518f899b3b80cb62bdc3b5e8514f3bc to your computer and use it in GitHub Desktop.
TimeSpan overflow checks
This file contains 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
public sealed class CheckedOverflowChecks : TimeSpanOverflowChecksContext | |
{ | |
public static TimeSpan Interval(int days = 0, int hours = 0, long minutes = 0, long seconds = 0, | |
long milliseconds = 0, long microseconds = 0) | |
{ | |
try | |
{ | |
long ticks = checked((long)days * TicksPerDay | |
+ (long)hours * TicksPerDay | |
+ minutes * TicksPerMinute | |
+ seconds * TicksPerSecond | |
+ milliseconds * TicksPerMillisecond | |
+ microseconds * TicksPerMicrosecond); | |
return new TimeSpan(ticks); | |
} | |
catch (OverflowException) | |
{ | |
const string message = "The timespan is too long and resulted in an overflow."; | |
throw new ArgumentOutOfRangeException(null, message); | |
} | |
} | |
} |
This file contains 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
public sealed class Int128OverflowChecks : TimeSpanOverflowChecksContext | |
{ | |
public static TimeSpan Interval(int days = 0, int hours = 0, long minutes = 0, long seconds = 0, | |
long milliseconds = 0, long microseconds = 0) | |
{ | |
Int128 ticks = (Int128)days * TicksPerDay | |
+ (Int128)hours * TicksPerHour | |
+ (Int128)minutes * TicksPerMinute | |
+ (Int128)seconds * TicksPerSecond | |
+ (Int128)milliseconds * TicksPerMillisecond | |
+ (Int128)microseconds * TicksPerMicrosecond; | |
if (ticks < TimeSpan.MinValue.Ticks || ticks > TimeSpan.MaxValue.Ticks) | |
ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong(); | |
return new TimeSpan((long)ticks); | |
} | |
public static TimeSpan SmartInterval(int days = 0, int hours = 0, long minutes = 0, long seconds = 0, | |
long milliseconds = 0, long microseconds = 0) | |
{ | |
Int128 ticks = default; | |
if (days != 0) | |
{ | |
ticks += (Int128)days * TicksPerDay; | |
ThrowOnOverflow(ticks); | |
} | |
if (hours != 0) | |
{ | |
ticks += (Int128)hours * TicksPerHour; | |
ThrowOnOverflow(ticks); | |
} | |
if (minutes != 0) | |
{ | |
ticks += (Int128)minutes * TicksPerMinute; | |
ThrowOnOverflow(ticks); | |
} | |
if (seconds != 0) | |
{ | |
ticks += (Int128)seconds * TicksPerSecond; | |
ThrowOnOverflow(ticks); | |
} | |
if (milliseconds != 0) | |
{ | |
ticks += (Int128)milliseconds * TicksPerMillisecond; | |
ThrowOnOverflow(ticks); | |
} | |
if (microseconds != 0) | |
{ | |
ticks += (Int128)microseconds * TicksPerMicrosecond; | |
ThrowOnOverflow(ticks); | |
} | |
return new TimeSpan((long)ticks); | |
} | |
private static void ThrowOnOverflow(Int128 ticks) | |
{ | |
if (ticks < TimeSpan.MinValue.Ticks || ticks > TimeSpan.MaxValue.Ticks) | |
ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong(); | |
} | |
} |
This file contains 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
public sealed class ManualOverflowChecks : TimeSpanOverflowChecksContext | |
{ | |
public static TimeSpan Interval(int days = 0, int hours = 0, long minutes = 0, long seconds = 0, | |
long milliseconds = 0, long microseconds = 0) | |
{ | |
ValidateRange(days, MinDays, MaxDays); | |
ValidateRange(hours, MinHours, MaxHours); | |
ValidateRange(minutes, MinMinutes, MaxMinutes); | |
ValidateRange(seconds, MinSeconds, MaxSeconds); | |
ValidateRange(milliseconds, MinMilliSeconds, MaxMilliSeconds); | |
ValidateRange(microseconds, MinMicroSeconds, MaxMicroSeconds); | |
long totalTicks = (long)days * TicksPerDay; | |
AddTicks((long)hours * TicksPerHour); | |
AddTicks(minutes * TicksPerMinute); | |
AddTicks(seconds * TicksPerSecond); | |
AddTicks(milliseconds * TicksPerMillisecond); | |
AddTicks(microseconds * TicksPerMicrosecond); | |
return new TimeSpan(totalTicks); | |
void AddTicks(long ticksToAdd) | |
{ | |
long previousTotalTicks = totalTicks; | |
totalTicks += ticksToAdd; | |
if (previousTotalTicks >> 63 == ticksToAdd >> 63 && previousTotalTicks >> 63 != totalTicks >> 63) | |
ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong(); | |
} | |
} | |
private static void ValidateRange(long value, long min, long max) | |
{ | |
if (value < min || value > max) | |
ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong(); | |
} | |
} |
This file contains 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
public abstract class TimeSpanOverflowChecksContext | |
{ | |
protected const long TicksPerMicrosecond = 10; | |
protected const long TicksPerMillisecond = TicksPerMicrosecond * 1000; | |
protected const long TicksPerSecond = TicksPerMillisecond * 1000; | |
protected const long TicksPerMinute = TicksPerSecond * 60; | |
protected const long TicksPerHour = TicksPerMinute * 60; | |
protected const long TicksPerDay = TicksPerHour * 24; | |
internal const long MaxDays = long.MaxValue / TicksPerDay; | |
internal const long MinDays = long.MinValue / TicksPerDay; | |
internal const long MaxHours = long.MaxValue / TicksPerHour; | |
internal const long MinHours = long.MinValue / TicksPerHour; | |
internal const long MaxMinutes = long.MaxValue / TicksPerMinute; | |
internal const long MinMinutes = long.MinValue / TicksPerMinute; | |
internal const long MaxSeconds = long.MaxValue / TicksPerSecond; | |
internal const long MinSeconds = long.MinValue / TicksPerSecond; | |
internal const long MaxMilliSeconds = long.MaxValue / TicksPerMillisecond; | |
internal const long MinMilliSeconds = long.MinValue / TicksPerMillisecond; | |
internal const long MaxMicroSeconds = long.MaxValue / TicksPerMicrosecond; | |
internal const long MinMicroSeconds = long.MinValue / TicksPerMicrosecond; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment