It's obvious, use TimeSpans to measure time
I know, this is probably not news to anyone. TimeSpan
is the native .NET type to represent
time intervals. But answer quickly, SqlCommand.CommandTimeout
represents the interval in
milliseconds, seconds, or minutes? What about System.Timers.Timer.Interval
?
To circumvent this situation we see all sorts of API design contortions, like trying to standardize all time units to the same unit, which sometimes is not viable, or using unnatural affixes when naming the class members, for example.
class CalendarEvent { public string Name { get; set; } public int DurationMinutes { get; set; } } //or.. class EquipmentError { public int ErrorCode { get; set; } public double MillisecondsTotal { get; set; } } //or... class ProjectPhase { public int ProjectID { get; set; } public string PhaseName { get; set; } public int PhaseWeeksDuration { get; set; } }
I think this stinks. Why do we constantly ignore the TimeSpan
structure? I know it's
kind of the bastard child of the System namespace. It lacks for example string formats. It's larger
than a simple Int32
. But the complete annihilation of any doubt as to what time unit
we are using is worth all that.
The previous examples could be made clearer with TimeSpan
s.
class CalendarEvent { public string Name { get; set; } public TimeSpan Duration { get; set; } } //or.. class EquipmentError { public int ErrorCode { get; set; } public TimeSpan TotalTime { get; set; } } //or... class ProjectPhase { public int ProjectID { get; set; } public string PhaseName { get; set; } public TimeSpan PhaseDuration { get; set; } }
But let's not stop there. We can simplify our lives by, for example, creating some extension methods to
deal with time interval tasks. I don't show below, but we could very well write an extension method to
fix the lack of a TimeSpan.ToString(string format)
method.
using System; namespace Utils.Extensions.Time { public static class TimespanExt { public static TimeSpan Minutes(this int interval) { return Minutes((double)interval); } public static TimeSpan Minutes(this double interval) { return TimeSpan.FromMinutes(interval); } public static TimeSpan Seconds(this int interval) { return Seconds((double)interval); } public static TimeSpan Seconds(this double interval) { return TimeSpan.FromSeconds(interval); } //.. a metric ton more utility methods like these... } }
With these extension methods, we get some handy syntax to ease the creation of TimeSpan
s.
TimeSpan interval = 5.Seconds(); TimeSpan elapsedTime = 0.7.Minutes();
And don't forget to use the Nulalble<TimeSpan>
, a.k.a. TimeSpan?
when
the interval is optional. I think the nullable is clearer than using TimeSpan.Zero
(or
TimeSpan.MinValue
— argh!!!) to represent unknown or missing values.