diff --git a/src/Spring/Spring.Core/Core/TypeConversion/TimeSpanConverter.cs b/src/Spring/Spring.Core/Core/TypeConversion/TimeSpanConverter.cs
index b2c1a122..ea13f38e 100644
--- a/src/Spring/Spring.Core/Core/TypeConversion/TimeSpanConverter.cs
+++ b/src/Spring/Spring.Core/Core/TypeConversion/TimeSpanConverter.cs
@@ -23,24 +23,239 @@
using System;
using System.ComponentModel;
using System.Globalization;
+using System.Text.RegularExpressions;
#endregion
namespace Spring.Core.TypeConversion
{
+ #region Specifier parsers
+
+ #if NET_1_1
+
+ ///
+ /// Nullable TimeSpan
+ ///
+ ///
+ /// Can be replaced with a TimeSpan? in .NET 2
+ ///
+ class TimeSpanNullable {
+
+ readonly bool _hasValue;
+ readonly TimeSpan _value;
+
+ ///
+ /// ctor without Value;
+ ///
+ public TimeSpanNullable() {
+ _hasValue = false;
+ }
+
+ ///
+ /// ctor with Value
+ ///
+ ///
+ public TimeSpanNullable(TimeSpan timeSpan) {
+ _hasValue = true;
+ _value = timeSpan;
+ }
+
+ ///
+ /// HasValue
+ ///
+ public bool HasValue {
+ get { return _hasValue; }
+ }
+
+ ///
+ /// Value if HasValue==true
+ ///
+ public TimeSpan Value {
+ get { return _value; }
+ }
+ }
+
+ #else
+
+ using TimeSpanNullable = Nullable;
+
+ #endif
+
+
+ ///
+ /// Base parser for custom specifiers.
+ ///
+ abstract class SpecifierParser
+ {
+ const RegexOptions ParsingOptions = RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.IgnoreCase;
+
+ ///
+ /// Specifier
+ ///
+ public abstract string Specifier { get; }
+
+ ///
+ /// Convert int value to a Timespan based on the specifier
+ ///
+ ///
+ ///
+ public abstract TimeSpan Parse(int value);
+
+ ///
+ /// Check if the string contains the specifier and
+ ///
+ ///
+ ///
+ public TimeSpanNullable Match(string value)
+ {
+ string regex = @"^(\d+)" + Specifier + "$";
+ Match match = Regex.Match(value, regex, ParsingOptions);
+
+ if (!match.Success) return new TimeSpanNullable();
+
+ return new TimeSpanNullable(Parse(int.Parse(match.Groups[1].Value)));
+ }
+
+ }
+
+ ///
+ /// Recognize 10d as ten days
+ ///
+ class DaySpecifier: SpecifierParser
+ {
+ ///
+ /// Day specifier: d
+ ///
+ public override string Specifier
+ {
+ get { return "d"; }
+ }
+
+ ///
+ /// Parse value as days
+ ///
+ /// Timespan in days
+ ///
+ public override TimeSpan Parse(int value)
+ {
+ return TimeSpan.FromDays(value);
+ }
+ }
+
+ ///
+ /// Recognize 10h as ten hours
+ ///
+ class HourSpecifier : SpecifierParser
+ {
+ ///
+ /// Hour specifier: h
+ ///
+ public override string Specifier
+ {
+ get { return "h"; }
+ }
+
+ ///
+ /// Parse value as hours
+ ///
+ /// Timespan in hours
+ ///
+ public override TimeSpan Parse(int value)
+ {
+ return TimeSpan.FromHours(value);
+ }
+ }
+
+ ///
+ /// Recognize 10m as ten minutes
+ ///
+ class MinuteSpecifier : SpecifierParser
+ {
+ ///
+ /// Minute specifier: m
+ ///
+ public override string Specifier
+ {
+ get { return "m"; }
+ }
+
+ ///
+ /// Parse value as minutes
+ ///
+ /// Timespan in minutes
+ ///
+ public override TimeSpan Parse(int value)
+ {
+ return TimeSpan.FromMinutes(value);
+ }
+ }
+
+ ///
+ /// Recognize 10s as ten seconds
+ ///
+ class SecondSpecifier : SpecifierParser
+ {
+ ///
+ /// Second specifier: s
+ ///
+ public override string Specifier
+ {
+ get { return "s"; }
+ }
+
+ ///
+ /// Parse value as seconds
+ ///
+ /// Timespan in seconds
+ ///
+ public override TimeSpan Parse(int value)
+ {
+ return TimeSpan.FromSeconds(value);
+ }
+ }
+
+ ///
+ /// Recognize 10ms as ten milliseconds
+ ///
+ class MillisecondSpecifier : SpecifierParser
+ {
+ ///
+ /// Millisecond specifier: ms
+ ///
+ public override string Specifier
+ {
+ get { return "ms"; }
+ }
+
+ ///
+ /// Parse value as milliseconds
+ ///
+ /// Timespan in milliseconds
+ ///
+ public override TimeSpan Parse(int value)
+ {
+ return TimeSpan.FromMilliseconds(value);
+ }
+ }
+
+ #endregion
+
///
/// Converter for instances.
///
/// Bruno Baia
+ /// Roberto Paterlini
public class TimeSpanConverter : System.ComponentModel.TimeSpanConverter
{
#region Constants
- private const string DaySpecifier = "d";
- private const string HourSpecifier = "h";
- private const string MinuteSpecifier = "m";
- private const string SecondSpecifier = "s";
- private const string MillisecondSpecifier = "ms";
+ static readonly SpecifierParser[] Specifiers = {
+ new DaySpecifier(),
+ new HourSpecifier(),
+ new MinuteSpecifier(),
+ new SecondSpecifier(),
+ new MillisecondSpecifier()
+ };
#endregion
@@ -77,26 +292,17 @@ namespace Spring.Core.TypeConversion
ITypeDescriptorContext context,
CultureInfo culture, object value)
{
- if (value is string)
+ string stringValue = value as string;
+ if (stringValue!=null)
{
try
{
- string timeSpan = ((string)value).ToLower();
- int specifierLengh = (timeSpan.EndsWith(MillisecondSpecifier)) ? 2 : 1;
- int time = int.Parse(timeSpan.Substring(0, timeSpan.Length - specifierLengh));
+ stringValue = stringValue.Trim();
- switch (timeSpan.Substring(timeSpan.Length - specifierLengh, specifierLengh))
+ foreach (SpecifierParser specifierParser in Specifiers)
{
- case MillisecondSpecifier:
- return TimeSpan.FromMilliseconds((double)time);
- case SecondSpecifier:
- return TimeSpan.FromSeconds((double)time);
- case MinuteSpecifier:
- return TimeSpan.FromMinutes((double)time);
- case HourSpecifier:
- return TimeSpan.FromHours((double)time);
- case DaySpecifier:
- return TimeSpan.FromDays((double)time);
+ TimeSpanNullable res = specifierParser.Match(stringValue);
+ if (res.HasValue) return res.Value;
}
}
catch { }
diff --git a/test/Spring/Spring.Core.Tests/Core/TypeConversion/TimeSpanConverterTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeConversion/TimeSpanConverterTests.cs
index 9bbfa346..c06327e1 100644
--- a/test/Spring/Spring.Core.Tests/Core/TypeConversion/TimeSpanConverterTests.cs
+++ b/test/Spring/Spring.Core.Tests/Core/TypeConversion/TimeSpanConverterTests.cs
@@ -21,7 +21,7 @@
#region Imports
using System;
-using System.Reflection;
+
using NUnit.Framework;
#endregion
@@ -113,10 +113,16 @@ namespace Spring.Core.TypeConversion
public void ConvertFromStringWithHourSpecifier()
{
TimeSpanConverter tsc = new TimeSpanConverter();
+
object timeSpan = tsc.ConvertFrom("1H");
Assert.IsNotNull(timeSpan);
Assert.IsTrue(timeSpan is TimeSpan);
Assert.AreEqual(TimeSpan.FromHours(1), (TimeSpan)timeSpan);
+
+ tsc.ConvertFrom("1h");
+ Assert.IsNotNull(timeSpan);
+ Assert.IsTrue(timeSpan is TimeSpan);
+ Assert.AreEqual(TimeSpan.FromHours(1), (TimeSpan)timeSpan);
}
[Test]