Tôi đã thêm một vài cải tiến mã Carles' và muốn chia sẻ chúng ở đây trong trường hợp chúng hữu ích cho người khác.
- Đảm bảo rằng nếu không có mẫu phân tích thành công thời gian, sau đó vẫn gọi là cơ sở để hiển thị một lỗi xác nhận (nếu không thì giá trị còn lại như
TimeSpan.Zero
và không có lỗi xác nhận nâng lên.)
- Sử dụng một vòng lặp thay bị xích
if
s.
- Hỗ trợ việc sử dụng
AM
và PM
đủ.
- Bỏ qua khoảng trắng.
Dưới đây là các mã:
public sealed class TimeSpanModelBinder : DefaultModelBinder
{
private const DateTimeStyles _dateTimeStyles = DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal | DateTimeStyles.NoCurrentDateDefault;
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
{
var form = controllerContext.HttpContext.Request.Form;
if (propertyDescriptor.PropertyType.Equals(typeof(TimeSpan?)) || propertyDescriptor.PropertyType.Equals(typeof(TimeSpan)))
{
var text = form[propertyDescriptor.Name];
TimeSpan time;
if (text != null && TryParseTime(text, out time))
{
SetProperty(controllerContext, bindingContext, propertyDescriptor, time);
return;
}
}
// Either a different type, or we couldn't parse the string.
base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
}
public static bool TryParseTime(string text, out TimeSpan time)
{
if (text == null)
throw new ArgumentNullException("text");
var formats = new[] {
"HH:mm", "HH.mm", "HHmm", "HH,mm", "HH",
"H:mm", "H.mm", "H,mm",
"hh:mmtt", "hh.mmtt", "hhmmtt", "hh,mmtt", "hhtt",
"h:mmtt", "h.mmtt", "hmmtt", "h,mmtt", "htt"
};
text = Regex.Replace(text, "([^0-9]|^)([0-9])([0-9]{2})([^0-9]|$)", "$1$2:$3$4");
text = Regex.Replace(text, "^[0-9]$", "0$0");
foreach (var format in formats)
{
DateTime value;
if (DateTime.TryParseExact(text, format, CultureInfo.InvariantCulture, _dateTimeStyles, out value))
{
time = value.TimeOfDay;
return true;
}
}
time = TimeSpan.Zero;
return false;
}
}
Điều này có vẻ một chút trên đầu trang, nhưng tôi muốn người dùng của tôi để có thể nhập khá nhiều bất cứ điều gì và có ứng dụng của tôi làm việc nó ra.
Nó có thể được áp dụng cho tất cả các DateTime
trường thông qua mã này trong Global.asax.cs
:
ModelBinders.Binders.Add(typeof(TimeSpan), new TimeSpanModelBinder());
Hoặc chỉ cần trên một số phương pháp hành động cụ thể:
public ActionResult Save([ModelBinder(typeof(TimeSpanModelBinder))] MyModel model)
{ ... }
và đây là một thử nghiệm đơn vị đơn giản chỉ để xác nhận một số đầu vào/đầu ra tiềm năng:
[TestMethod]
public void TimeSpanParsing()
{
var testData = new[] {
new { Text = "100", Time = new TimeSpan(1, 0, 0) },
new { Text = "10:00 PM", Time = new TimeSpan(22, 0, 0) },
new { Text = "2", Time = new TimeSpan(2, 0, 0) },
new { Text = "10", Time = new TimeSpan(10, 0, 0) },
new { Text = "100PM", Time = new TimeSpan(13, 0, 0) },
new { Text = "1000", Time = new TimeSpan(10, 0, 0) },
new { Text = "10:00", Time = new TimeSpan(10, 0, 0) },
new { Text = "10.00", Time = new TimeSpan(10, 0, 0) },
new { Text = "13:00", Time = new TimeSpan(13, 0, 0) },
new { Text = "13.00", Time = new TimeSpan(13, 0, 0) },
new { Text = "10 PM", Time = new TimeSpan(22, 0, 0) },
new { Text = " 10\t PM ", Time = new TimeSpan(22, 0, 0) },
new { Text = "10PM", Time = new TimeSpan(22, 0, 0) },
new { Text = "1PM", Time = new TimeSpan(13, 0, 0) },
new { Text = "1 am", Time = new TimeSpan(1, 0, 0) },
new { Text = "1 AM", Time = new TimeSpan(1, 0, 0) },
new { Text = "1 pm", Time = new TimeSpan(13, 0, 0) },
new { Text = "1 PM", Time = new TimeSpan(13, 0, 0) },
new { Text = "01 PM", Time = new TimeSpan(13, 0, 0) },
new { Text = "0100 PM", Time = new TimeSpan(13, 0, 0) },
new { Text = "01.00 PM", Time = new TimeSpan(13, 0, 0) },
new { Text = "01.00PM", Time = new TimeSpan(13, 0, 0) },
new { Text = "1:00PM", Time = new TimeSpan(13, 0, 0) },
new { Text = "1:00 PM", Time = new TimeSpan(13, 0, 0) },
new { Text = "12,34", Time = new TimeSpan(12, 34, 0) },
new { Text = "1012PM", Time = new TimeSpan(22, 12, 0) },
};
foreach (var test in testData)
{
try
{
TimeSpan time;
Assert.IsTrue(TimeSpanModelBinder.TryParseTime(test.Text, out time), "Should parse {0}", test.Text);
if (!Equals(time, test.Time))
Assert.Fail("Time parse failed. Expected {0} but got {1}", test.Time, time);
}
catch (FormatException)
{
Assert.Fail("Received format exception with text {0}", test.Text);
}
}
}
Hy vọng rằng sẽ giúp ai đó ra ngoài.
Tuyệt vời! Đây là con đường để đi ... –