Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 64 additions & 26 deletions src/Polyfill/TimeSpanPolyfill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,64 @@ static TimeSpan TicksFromMicroseconds(decimal totalMicroseconds)
return new((long)ticks);
}

// The decimal accumulation above costs hundreds of nanoseconds. When every component is small
// enough that its own tick count is at most an eighth of long.MaxValue, the (at most six)
// components cannot overflow an Int64 between them, so the ticks can be summed directly and
// the result is always in range. Anything larger takes the decimal path, which decides
// whether the total overflows.
const long MaxFastPathTicks = long.MaxValue / 8;

static bool IsWithin(long value, long bound) =>
value >= -bound && value <= bound;

static TimeSpan FromComponents(long days, long hours, long minutes, long seconds, long milliseconds, long microseconds)
{
if (IsWithin(days, MaxFastPathTicks / TimeSpan.TicksPerDay) &&
IsWithin(hours, MaxFastPathTicks / TimeSpan.TicksPerHour) &&
IsWithin(minutes, MaxFastPathTicks / TimeSpan.TicksPerMinute) &&
IsWithin(seconds, MaxFastPathTicks / TimeSpan.TicksPerSecond) &&
IsWithin(milliseconds, MaxFastPathTicks / TimeSpan.TicksPerMillisecond) &&
IsWithin(microseconds, MaxFastPathTicks / MicrosecondsToTicks))
{
return new(
days * TimeSpan.TicksPerDay +
hours * TimeSpan.TicksPerHour +
minutes * TimeSpan.TicksPerMinute +
seconds * TimeSpan.TicksPerSecond +
milliseconds * TimeSpan.TicksPerMillisecond +
microseconds * MicrosecondsToTicks);
}

// Components an overload does not have arrive as zero; leave them out of the decimal sum
decimal total = microseconds;
if (days != 0)
{
total += (decimal)days * MicrosecondsPerDay;
}

if (hours != 0)
{
total += (decimal)hours * MicrosecondsPerHour;
}

if (minutes != 0)
{
total += (decimal)minutes * MicrosecondsPerMinute;
}

if (seconds != 0)
{
total += (decimal)seconds * MicrosecondsPerSecond;
}

if (milliseconds != 0)
{
total += (decimal)milliseconds * MicrosecondsPerMillisecond;
}

return TicksFromMicroseconds(total);
}

extension(TimeSpan)
{
/// <summary>
Expand Down Expand Up @@ -166,62 +224,42 @@ static TimeSpan TicksFromMicroseconds(decimal totalMicroseconds)
/// </summary>
//Link: https://learn.microsoft.com/en-us/dotnet/api/system.timespan.fromdays?view=net-11.0#system-timespan-fromdays(system-int32-system-int32-system-int64-system-int64-system-int64-system-int64)
public static TimeSpan FromDays(int days, int hours = 0, long minutes = 0, long seconds = 0, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)days * MicrosecondsPerDay +
(decimal)hours * MicrosecondsPerHour +
(decimal)minutes * MicrosecondsPerMinute +
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(days, hours, minutes, seconds, milliseconds, microseconds);

/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of hours, minutes, seconds, milliseconds, and microseconds.
/// </summary>
//Link: https://learn.microsoft.com/en-us/dotnet/api/system.timespan.fromhours?view=net-11.0#system-timespan-fromhours(system-int32-system-int64-system-int64-system-int64-system-int64)
public static TimeSpan FromHours(int hours, long minutes = 0, long seconds = 0, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)hours * MicrosecondsPerHour +
(decimal)minutes * MicrosecondsPerMinute +
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, hours, minutes, seconds, milliseconds, microseconds);

/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of minutes, seconds, milliseconds, and microseconds.
/// </summary>
//Link: https://learn.microsoft.com/en-us/dotnet/api/system.timespan.fromminutes?view=net-11.0#system-timespan-fromminutes(system-int64-system-int64-system-int64-system-int64)
public static TimeSpan FromMinutes(long minutes, long seconds = 0, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)minutes * MicrosecondsPerMinute +
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, 0, minutes, seconds, milliseconds, microseconds);

/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of seconds, milliseconds, and microseconds.
/// </summary>
//Link: https://learn.microsoft.com/en-us/dotnet/api/system.timespan.fromseconds?view=net-11.0#system-timespan-fromseconds(system-int64-system-int64-system-int64)
public static TimeSpan FromSeconds(long seconds, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, 0, 0, seconds, milliseconds, microseconds);

/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of milliseconds and microseconds.
/// </summary>
//Link: https://learn.microsoft.com/en-us/dotnet/api/system.timespan.frommilliseconds?view=net-11.0#system-timespan-frommilliseconds(system-int64-system-int64)
public static TimeSpan FromMilliseconds(long milliseconds, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, 0, 0, 0, milliseconds, microseconds);

/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of microseconds.
/// </summary>
//Link: https://learn.microsoft.com/en-us/dotnet/api/system.timespan.frommicroseconds?view=net-11.0#system-timespan-frommicroseconds(system-int64)
public static TimeSpan FromMicroseconds(long microseconds) =>
TicksFromMicroseconds(microseconds);
FromComponents(0, 0, 0, 0, 0, microseconds);
}
#endif
}
75 changes: 49 additions & 26 deletions src/Split/net461/TimeSpanPolyfill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,49 @@ static TimeSpan TicksFromMicroseconds(decimal totalMicroseconds)
}
return new((long)ticks);
}
const long MaxFastPathTicks = long.MaxValue / 8;
static bool IsWithin(long value, long bound) =>
value >= -bound && value <= bound;
static TimeSpan FromComponents(long days, long hours, long minutes, long seconds, long milliseconds, long microseconds)
{
if (IsWithin(days, MaxFastPathTicks / TimeSpan.TicksPerDay) &&
IsWithin(hours, MaxFastPathTicks / TimeSpan.TicksPerHour) &&
IsWithin(minutes, MaxFastPathTicks / TimeSpan.TicksPerMinute) &&
IsWithin(seconds, MaxFastPathTicks / TimeSpan.TicksPerSecond) &&
IsWithin(milliseconds, MaxFastPathTicks / TimeSpan.TicksPerMillisecond) &&
IsWithin(microseconds, MaxFastPathTicks / MicrosecondsToTicks))
{
return new(
days * TimeSpan.TicksPerDay +
hours * TimeSpan.TicksPerHour +
minutes * TimeSpan.TicksPerMinute +
seconds * TimeSpan.TicksPerSecond +
milliseconds * TimeSpan.TicksPerMillisecond +
microseconds * MicrosecondsToTicks);
}
decimal total = microseconds;
if (days != 0)
{
total += (decimal)days * MicrosecondsPerDay;
}
if (hours != 0)
{
total += (decimal)hours * MicrosecondsPerHour;
}
if (minutes != 0)
{
total += (decimal)minutes * MicrosecondsPerMinute;
}
if (seconds != 0)
{
total += (decimal)seconds * MicrosecondsPerSecond;
}
if (milliseconds != 0)
{
total += (decimal)milliseconds * MicrosecondsPerMillisecond;
}
return TicksFromMicroseconds(total);
}
extension(TimeSpan)
{
/// <summary>
Expand Down Expand Up @@ -104,51 +147,31 @@ static TimeSpan TicksFromMicroseconds(decimal totalMicroseconds)
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of days, hours, minutes, seconds, milliseconds, and microseconds.
/// </summary>
public static TimeSpan FromDays(int days, int hours = 0, long minutes = 0, long seconds = 0, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)days * MicrosecondsPerDay +
(decimal)hours * MicrosecondsPerHour +
(decimal)minutes * MicrosecondsPerMinute +
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(days, hours, minutes, seconds, milliseconds, microseconds);
/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of hours, minutes, seconds, milliseconds, and microseconds.
/// </summary>
public static TimeSpan FromHours(int hours, long minutes = 0, long seconds = 0, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)hours * MicrosecondsPerHour +
(decimal)minutes * MicrosecondsPerMinute +
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, hours, minutes, seconds, milliseconds, microseconds);
/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of minutes, seconds, milliseconds, and microseconds.
/// </summary>
public static TimeSpan FromMinutes(long minutes, long seconds = 0, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)minutes * MicrosecondsPerMinute +
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, 0, minutes, seconds, milliseconds, microseconds);
/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of seconds, milliseconds, and microseconds.
/// </summary>
public static TimeSpan FromSeconds(long seconds, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, 0, 0, seconds, milliseconds, microseconds);
/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of milliseconds and microseconds.
/// </summary>
public static TimeSpan FromMilliseconds(long milliseconds, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, 0, 0, 0, milliseconds, microseconds);
/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of microseconds.
/// </summary>
public static TimeSpan FromMicroseconds(long microseconds) =>
TicksFromMicroseconds(microseconds);
FromComponents(0, 0, 0, 0, 0, microseconds);
}
}
75 changes: 49 additions & 26 deletions src/Split/net462/TimeSpanPolyfill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,49 @@ static TimeSpan TicksFromMicroseconds(decimal totalMicroseconds)
}
return new((long)ticks);
}
const long MaxFastPathTicks = long.MaxValue / 8;
static bool IsWithin(long value, long bound) =>
value >= -bound && value <= bound;
static TimeSpan FromComponents(long days, long hours, long minutes, long seconds, long milliseconds, long microseconds)
{
if (IsWithin(days, MaxFastPathTicks / TimeSpan.TicksPerDay) &&
IsWithin(hours, MaxFastPathTicks / TimeSpan.TicksPerHour) &&
IsWithin(minutes, MaxFastPathTicks / TimeSpan.TicksPerMinute) &&
IsWithin(seconds, MaxFastPathTicks / TimeSpan.TicksPerSecond) &&
IsWithin(milliseconds, MaxFastPathTicks / TimeSpan.TicksPerMillisecond) &&
IsWithin(microseconds, MaxFastPathTicks / MicrosecondsToTicks))
{
return new(
days * TimeSpan.TicksPerDay +
hours * TimeSpan.TicksPerHour +
minutes * TimeSpan.TicksPerMinute +
seconds * TimeSpan.TicksPerSecond +
milliseconds * TimeSpan.TicksPerMillisecond +
microseconds * MicrosecondsToTicks);
}
decimal total = microseconds;
if (days != 0)
{
total += (decimal)days * MicrosecondsPerDay;
}
if (hours != 0)
{
total += (decimal)hours * MicrosecondsPerHour;
}
if (minutes != 0)
{
total += (decimal)minutes * MicrosecondsPerMinute;
}
if (seconds != 0)
{
total += (decimal)seconds * MicrosecondsPerSecond;
}
if (milliseconds != 0)
{
total += (decimal)milliseconds * MicrosecondsPerMillisecond;
}
return TicksFromMicroseconds(total);
}
extension(TimeSpan)
{
/// <summary>
Expand Down Expand Up @@ -104,51 +147,31 @@ static TimeSpan TicksFromMicroseconds(decimal totalMicroseconds)
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of days, hours, minutes, seconds, milliseconds, and microseconds.
/// </summary>
public static TimeSpan FromDays(int days, int hours = 0, long minutes = 0, long seconds = 0, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)days * MicrosecondsPerDay +
(decimal)hours * MicrosecondsPerHour +
(decimal)minutes * MicrosecondsPerMinute +
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(days, hours, minutes, seconds, milliseconds, microseconds);
/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of hours, minutes, seconds, milliseconds, and microseconds.
/// </summary>
public static TimeSpan FromHours(int hours, long minutes = 0, long seconds = 0, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)hours * MicrosecondsPerHour +
(decimal)minutes * MicrosecondsPerMinute +
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, hours, minutes, seconds, milliseconds, microseconds);
/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of minutes, seconds, milliseconds, and microseconds.
/// </summary>
public static TimeSpan FromMinutes(long minutes, long seconds = 0, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)minutes * MicrosecondsPerMinute +
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, 0, minutes, seconds, milliseconds, microseconds);
/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of seconds, milliseconds, and microseconds.
/// </summary>
public static TimeSpan FromSeconds(long seconds, long milliseconds = 0, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)seconds * MicrosecondsPerSecond +
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, 0, 0, seconds, milliseconds, microseconds);
/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of milliseconds and microseconds.
/// </summary>
public static TimeSpan FromMilliseconds(long milliseconds, long microseconds = 0) =>
TicksFromMicroseconds(
(decimal)milliseconds * MicrosecondsPerMillisecond +
microseconds);
FromComponents(0, 0, 0, 0, milliseconds, microseconds);
/// <summary>
/// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of microseconds.
/// </summary>
public static TimeSpan FromMicroseconds(long microseconds) =>
TicksFromMicroseconds(microseconds);
FromComponents(0, 0, 0, 0, 0, microseconds);
}
}
Loading
Loading