Devlico.Us
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @devlicious

Sergio Pereira

There are no half-solutions because there isn't half a problem


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



Comments

El Guapo said:

1. Timespan is not serializible

2. Timespan cannot be passed in SqlCommand argument

It's very limited because of these. You end up having to store "DurationInSeconds" anyway so you just use only that for simplicity.

# July 24, 2008 8:39 AM

Joshua Flanagan said:

This is a great point when it comes to the infrastructure timeout value examples.

However, when you start talking about your domain objects, I think using the TimeSpan may create an even more awkward API. Your domain should likely be intentionally constrained to the situations that make sense for it. If your domain always calls for ProjectPhases to be measured in weeks, it would help if the API would guide the user (developer) in that direction. if you use the TimeSpan. It tells the user that any time duration is possible and suggests a possible phase duration could be: 1 week, 3 days: 4 hours, 2 and seconds. I think it provides better documentation to use the slightly awkward PhasesWeeksDuration property, as opposed to a PhaseDuration property which has a bunch of ArgumentOutOfRange checks to to ensure the value is always a number of days divisible by 7.

# July 24, 2008 8:41 AM

sergiopereira said:

@El Guapo

1 - good point. That's another problem that comes with being the bastard child data type.

2 - Not a big problem, at least for me. I can always use TotalSeconds if that is what the underlying database needs. I prefer to not let the DB dictate my domain objects, if possible.

# July 24, 2008 9:12 AM

sergiopereira said:

@Joshua, in this case you don't really have a time interval, you have time boxes or a pre-defined time unit that everyone knows about. Probably a bad example on my part.

TimeSpans can't replace all forms of time measurement.

# July 24, 2008 9:15 AM

Dmitri said:

Definitely not the class for performance measurements, though :)

# August 2, 2008 10:40 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

Our Sponsors

Red-Gate!

Proudly Partnered With