Formatting MVC model TimeSpan field

SamiHuutoniemi picture SamiHuutoniemi · Jul 10, 2013 · Viewed 24.2k times · Source

I have a MVC page containing a few timepickers. These are stored in a list of objects in the model as nullable TimeSpan. The problem is that I get the timespans printed with seconds into the input fields. Is there some way to format these model properties so that I get the timespans printed in some other way (like 7:00, instead of 07:00:00)? Needless to say, my "suggestion" of [DisplayFormat...] didn't work. At least not the way I hoped.

The input fields are defined like this:

@Html.TextBoxFor(x => x.Shifts[i].Start)

The relevant part of the model looks like:

public class Workshift
{
    [DisplayFormat(Something here perhaps?)]
    public TimeSpan? Start { get; set; }
    public TimeSpan? End { get; set; }
    public TimeSpan? Pause { get; set; }
}

public class TimeRegistrationViewModel
{
    public List<Workshift> Shifts { get; set; }

    ...
}

Appreciate it as always!

Answer

Matt Johnson-Pint picture Matt Johnson-Pint · Jul 14, 2013
[DisplayFormat(DataFormatString="{0:hh\\:mm}", ApplyFormatInEditMode = true)]
public TimeSpan? Start { get; set; }

[DisplayFormat(DataFormatString="{0:hh\\:mm}", ApplyFormatInEditMode = true)]
public TimeSpan? End { get; set; }

[DisplayFormat(DataFormatString="{0:hh\\:mm}", ApplyFormatInEditMode = true)]
public TimeSpan? Pause { get; set; }

But do keep in mind that the primary purpose for TimeSpan is to represent a measured duration of time, not a time of day. This means that TimeSpan values can be longer than 24 hours. They can also be negative, to represent moving backwards on the timeline.

It's acceptable to use them as time-of-day, and is actually done by the framework itself (for example, DateTime.TimeOfDay). But when used this way, you should validate user input carefully. If you just rely on the data type, the user might be able to enter values that are valid time spans, but not valid day times. For example, -1.22:33:44 is a valid TimeSpan that represents 1 day, 22 hours, 33 minutes and 44 seconds in the past.

It would be so much easier if .Net had a native Time type, but it does not. Update: There is now a native TimeOfDay type in the System.Time package available in CoreFXLab.

Also, the TextBoxFor method will not pick up the data annotation. You can either directly specify the format string as a parameter, like this:

@Html.TextBoxFor(x => x.Shifts[i].Start, "{0:hh\\:mm}")

Or you can switch to EditorFor like this:

@Html.EditorFor(x => x.Shifts[i].Start)