diff --git a/nanoFramework.Json.Test/Converters/TimeSpanConverterTests.cs b/nanoFramework.Json.Test/Converters/TimeSpanConverterTests.cs
index 78eff95..4f126e8 100644
--- a/nanoFramework.Json.Test/Converters/TimeSpanConverterTests.cs
+++ b/nanoFramework.Json.Test/Converters/TimeSpanConverterTests.cs
@@ -3,6 +3,7 @@
// See LICENSE file in the project root for full license information.
//
+using nanoFramework.Json.Converters;
using nanoFramework.TestFramework;
using System;
@@ -12,26 +13,77 @@ namespace nanoFramework.Json.Test.Converters
public class TimeSpanConverterTests
{
[TestMethod]
- [DataRow("10:00:00", 10)]
- [DataRow("24:00:00", 24)]
- public void TimeSpanConverter_ToType_ShouldReturnValidData(string value, int expectedValueHours)
+ public void TimeSpanConverter_ToType_Should_Return_Valid_Data()
{
- var converter = new Json.Converters.TimeSpanConverter();
- var convertedValue = (TimeSpan)converter.ToType(value);
+ var values = new[]
+ {
+ "-1.02:03:04.005",
+ "1.02:03:04.0050000",
+ "4.03:02:01.654321",
+ "4.03:02:01.65432",
+ "4.03:02:01.6543",
+ "4.03:02:01.654",
+ "4.03:02:01.65",
+ "4.03:02:01.6",
+ "04:20:19",
+ "07:32",
+ };
- var expectedTimeSpanValue = TimeSpan.FromHours(expectedValueHours);
- Assert.AreEqual(expectedTimeSpanValue.Ticks, convertedValue.Ticks);
+ var expected = new[]
+ {
+ -new TimeSpan(1, 2, 3, 4, 5),
+ new TimeSpan(1, 2, 3, 4, 5),
+ new TimeSpan(4, 3, 2, 1, 654).Add(new TimeSpan(3210)),
+ new TimeSpan(4, 3, 2, 1, 654).Add(new TimeSpan(3200)),
+ new TimeSpan(4, 3, 2, 1, 654).Add(new TimeSpan(3000)),
+ new TimeSpan(4, 3, 2, 1, 654),
+ new TimeSpan(4, 3, 2, 1, 650),
+ new TimeSpan(4, 3, 2, 1, 600),
+ new TimeSpan(4, 20, 19),
+ new TimeSpan(7, 32, 0),
+ };
+
+ var sut = new TimeSpanConverter();
+
+ for (var i = 0; i < values.Length; i++)
+ {
+ var actual = (TimeSpan) sut.ToType(values[i]);
+
+ Assert.AreEqual(expected[i], actual);
+ }
}
[TestMethod]
- [DataRow(10, "\"10:00:00\"")]
- [DataRow(24, "\"24:00:00\"")]
- public void TimeSpanConverter_ToJson_Should_ReturnValidData(int valueHours, string expectedValue)
+ public void TimeSpanConverter_ToJson_Should_Return_Valid_Data()
{
- var converter = new Json.Converters.TimeSpanConverter();
- var convertedValue = converter.ToJson(TimeSpan.FromHours(valueHours));
+ var values = new[]
+ {
+ -new TimeSpan(1, 2, 3, 4, 5),
+ new TimeSpan(1, 2, 3, 4, 5),
+ new TimeSpan(4, 3, 2, 1, 654).Add(new TimeSpan(3210)),
+ new TimeSpan(4, 20, 19),
+ new TimeSpan(7, 32, 0),
+ new TimeSpan(0, 29, 0),
+ };
+
+ var expected = new[]
+ {
+ "\"-1.02:03:04.0050000\"",
+ "\"1.02:03:04.0050000\"",
+ "\"4.03:02:01.6543210\"",
+ "\"04:20:19\"",
+ "\"07:32:00\"",
+ "\"00:29:00\"",
+ };
+
+ var sut = new TimeSpanConverter();
+
+ for (var i = 0; i < values.Length; i++)
+ {
+ var actual = sut.ToJson(values[i]);
- Assert.AreEqual(expectedValue, convertedValue);
+ Assert.AreEqual(expected[i], actual);
+ }
}
}
}
diff --git a/nanoFramework.Json.Test/nanoFramework.Json.Test.nfproj b/nanoFramework.Json.Test/nanoFramework.Json.Test.nfproj
index 5d028b8..479cd3f 100644
--- a/nanoFramework.Json.Test/nanoFramework.Json.Test.nfproj
+++ b/nanoFramework.Json.Test/nanoFramework.Json.Test.nfproj
@@ -59,40 +59,34 @@
-
+
+
+
+
+
+
+
..\packages\nanoFramework.CoreLibrary.1.15.5\lib\mscorlib.dll
- True
-
+
..\packages\nanoFramework.System.Collections.1.5.31\lib\nanoFramework.System.Collections.dll
- True
-
+
..\packages\nanoFramework.System.Text.1.2.54\lib\nanoFramework.System.Text.dll
- True
-
+
..\packages\nanoFramework.TestFramework.2.1.94\lib\nanoFramework.TestFramework.dll
- True
-
+
..\packages\nanoFramework.TestFramework.2.1.94\lib\nanoFramework.UnitTestLauncher.exe
- True
-
+
..\packages\nanoFramework.System.IO.Streams.1.1.59\lib\System.IO.Streams.dll
- True
-
-
-
-
-
-
diff --git a/nanoFramework.Json/Converters/TimeSpanConverter.cs b/nanoFramework.Json/Converters/TimeSpanConverter.cs
index e2e467d..c576833 100644
--- a/nanoFramework.Json/Converters/TimeSpanConverter.cs
+++ b/nanoFramework.Json/Converters/TimeSpanConverter.cs
@@ -12,10 +12,7 @@ internal sealed class TimeSpanConverter : IConverter
///
///
///
- public string ToJson(object value)
- {
- return "\"" + value.ToString() + "\"";
- }
+ public string ToJson(object value) => $"\"{value}\"";
///
///
@@ -34,32 +31,34 @@ internal static TimeSpan ConvertFromString(string value)
{
// split string value with all possible separators
// format is: -ddddd.HH:mm:ss.fffffff
- var timeSpanBits = value.Split(':', '.');
+ var tokens = value.Split(':', '.');
// sanity check
- if (timeSpanBits.Length == 0)
+ if (tokens.Length == 0)
{
return TimeSpan.Zero;
}
// figure out where the separators are
- int indexOfFirstDot = value.IndexOf('.');
- int indexOfSecondDot = indexOfFirstDot > -1 ? value.IndexOf('.', indexOfFirstDot + 1) : -1;
- int indexOfFirstColon = value.IndexOf(':');
- int indexOfSecondColon = indexOfFirstColon > -1 ? value.IndexOf(':', indexOfFirstColon + 1) : -1;
+ var indexOfFirstDot = value.IndexOf('.');
+ var indexOfSecondDot = indexOfFirstDot > -1 ? value.IndexOf('.', indexOfFirstDot + 1) : -1;
+ var indexOfFirstColon = value.IndexOf(':');
+ var indexOfSecondColon = indexOfFirstColon > -1 ? value.IndexOf(':', indexOfFirstColon + 1) : -1;
// sanity check for separators: all have to be ahead of string start
- if (SeparatorCheck(timeSpanBits, indexOfFirstDot, indexOfSecondDot, indexOfFirstColon, indexOfSecondColon))
+ if (SeparatorCheck(tokens, indexOfFirstDot, indexOfSecondDot, indexOfFirstColon, indexOfSecondColon))
{
throw new InvalidCastException();
}
+ var isNegative = value.StartsWith("-");
+
// to have days, it has to have something before the 1st dot, or just have a single component
- bool hasDays = (indexOfFirstDot > 0 && indexOfFirstDot < indexOfFirstColon) || timeSpanBits.Length == 1;
- bool hasTicks = hasDays ? indexOfSecondDot > indexOfFirstDot : indexOfFirstDot > -1;
- bool hasHours = indexOfFirstColon > 0;
- bool hasMinutes = hasHours && indexOfFirstColon > -1;
- bool hasSeconds = hasMinutes && indexOfSecondColon > -1;
+ var hasDays = (indexOfFirstDot > 0 && indexOfFirstDot < indexOfFirstColon) || tokens.Length == 1;
+ var hasTicks = hasDays ? indexOfSecondDot > indexOfFirstDot : indexOfFirstDot > -1;
+ var hasHours = indexOfFirstColon > 0;
+ var hasMinutes = hasHours && indexOfFirstColon > -1;
+ var hasSeconds = hasMinutes && indexOfSecondColon > -1;
// sanity check for ticks without other time components
if (hasTicks && !hasHours)
@@ -68,20 +67,13 @@ internal static TimeSpan ConvertFromString(string value)
}
// let the parsing start!
- int days = 0;
- if (hasDays
- && !int.TryParse(timeSpanBits[0], out days))
- {
- throw new InvalidCastException();
- }
+ var tokenIndex = 0;
- // bump the index if days component is present
- int processIndex = hasDays ? 1 : 0;
-
- var hours = ParseValueFromString(hasHours, timeSpanBits, ref processIndex);
- var minutes = ParseValueFromString(hasMinutes, timeSpanBits, ref processIndex);
- var seconds = ParseValueFromString(hasSeconds, timeSpanBits, ref processIndex);
- var ticks = HandleTicks(timeSpanBits, hasTicks, processIndex);
+ var days = ParseToken(hasDays, tokens, ref tokenIndex);
+ var hours = ParseToken(hasHours, tokens, ref tokenIndex);
+ var minutes = ParseToken(hasMinutes, tokens, ref tokenIndex);
+ var seconds = ParseToken(hasSeconds, tokens, ref tokenIndex);
+ var ticks = ParseTicks(hasTicks, tokens, tokenIndex);
// sanity check for valid ranges
if (IsInvalidTimeSpan(hours, minutes, seconds))
@@ -90,77 +82,86 @@ internal static TimeSpan ConvertFromString(string value)
}
// we should have everything now
- return new TimeSpan(ticks).Add(new TimeSpan(days, hours, minutes, seconds, 0));
+ var timeSpan = new TimeSpan(days, hours, minutes, seconds, 0).Add(new TimeSpan(ticks));
+
+ return isNegative ? -timeSpan : timeSpan;
}
- private static int HandleTicks(string[] timeSpanBits, bool hasTicks, int processIndex)
+ private static bool IsInvalidTimeSpan(int hour, int minutes, int seconds)
{
- if (!hasTicks || processIndex > timeSpanBits.Length)
+ if (hour is < 0 or > 24)
{
- return 0;
+ return true;
}
- if (!int.TryParse(timeSpanBits[processIndex], out var ticks))
+ if (minutes is < 0 or >= 60)
{
- throw new InvalidCastException();
+ return true;
}
- // if ticks are under 999, that's milliseconds
- if (ticks < 1_000)
+ if (seconds is < 0 or >= 60)
{
- ticks *= 10_000;
+ return true;
}
- return ticks;
- }
-
- private static bool SeparatorCheck(string[] timeSpanBits, int indexOfFirstDot, int indexOfSecondDot, int indexOfFirstColon, int indexOfSecondColon)
- {
- return timeSpanBits.Length > 1
- && indexOfFirstDot <= 0
- && indexOfSecondDot <= 0
- && indexOfFirstColon <= 0
- && indexOfSecondColon <= 0;
+ return false;
}
- private static int ParseValueFromString(bool hasValue,string[] timeSpanBits, ref int processIndex)
+ private static int ParseTicks(bool hasTicks, string[] tokens, int tokenIndex)
{
- if (!hasValue)
+ if (!hasTicks || tokenIndex > tokens.Length)
{
return 0;
}
- if (processIndex > timeSpanBits.Length)
+ var token = tokens[tokenIndex];
+
+ if (token.Length > 7)
{
- return 0;
+ token = token.Substring(0, 7);
}
- if (!int.TryParse(timeSpanBits[processIndex++], out var value))
+ if (!int.TryParse(token, out var value))
{
throw new InvalidCastException();
}
- return value;
+ value = token.Length switch
+ {
+ 1 => value * 1_000_000,
+ 2 => value * 100_000,
+ 3 => value * 10_000,
+ 4 => value * 1_000,
+ 5 => value * 100,
+ 6 => value * 10,
+ _ => value
+ };
+
+ return value >= 0 ? value : value * -1;
}
- private static bool IsInvalidTimeSpan(int hour, int minutes, int seconds)
+ private static int ParseToken(bool hasValue, string[] tokens, ref int tokenIndex)
{
- if (hour < 0 || hour > 24)
+ if (!hasValue || tokenIndex > tokens.Length)
{
- return true;
+ return 0;
}
- if (minutes < 0 || minutes >= 60)
+ if (!int.TryParse(tokens[tokenIndex++], out var value))
{
- return true;
+ throw new InvalidCastException();
}
- if (seconds < 0 || seconds >= 60)
- {
- return true;
- }
+ return value >= 0 ? value : value * -1;
+ }
- return false;
+ private static bool SeparatorCheck(string[] tokens, int indexOfFirstDot, int indexOfSecondDot, int indexOfFirstColon, int indexOfSecondColon)
+ {
+ return tokens.Length > 1
+ && indexOfFirstDot <= 0
+ && indexOfSecondDot <= 0
+ && indexOfFirstColon <= 0
+ && indexOfSecondColon <= 0;
}
}
}