Sergio and the sigil

It's obvious, use TimeSpans to measure time

Posted by Sergio on 2008-07-24

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 TimeSpans.

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 TimeSpans.

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.