diff --git a/src/ServiceStack.Text/Support/TimeSpanConverter.cs b/src/ServiceStack.Text/Support/TimeSpanConverter.cs index 25314f90d..5b681101f 100644 --- a/src/ServiceStack.Text/Support/TimeSpanConverter.cs +++ b/src/ServiceStack.Text/Support/TimeSpanConverter.cs @@ -8,10 +8,11 @@ public class TimeSpanConverter { public static string ToXsdDuration(TimeSpan timeSpan) { - var sb = new StringBuilder("P"); + var sb = new StringBuilder(); - double ticks = timeSpan.Ticks; + sb.Append(timeSpan.Ticks < 0 ? "-P" : "P"); + double ticks = Math.Abs(timeSpan.Ticks); double totalSeconds = ticks / TimeSpan.TicksPerSecond; int wholeSeconds = (int) totalSeconds; int seconds = wholeSeconds; @@ -55,6 +56,7 @@ public static TimeSpan FromXsdDuration(string xsdDuration) int hours = 0; int minutes = 0; double seconds = 0; + var sign = (xsdDuration.StartsWith("-", StringComparison.Ordinal) ? -1 : 1); string[] t = xsdDuration.Substring(1).SplitOnFirst('T'); //strip P @@ -100,7 +102,7 @@ public static TimeSpan FromXsdDuration(string xsdDuration) + (minutes * 60) + (seconds); - var interval = (long) (totalSecs * TimeSpan.TicksPerSecond); + var interval = (long) (totalSecs * TimeSpan.TicksPerSecond * sign); return TimeSpan.FromTicks(interval); } diff --git a/tests/ServiceStack.Text.Tests/DateTimeOffsetAndTimeSpanTests.cs b/tests/ServiceStack.Text.Tests/DateTimeOffsetAndTimeSpanTests.cs index 2f14e4135..1467d30ce 100644 --- a/tests/ServiceStack.Text.Tests/DateTimeOffsetAndTimeSpanTests.cs +++ b/tests/ServiceStack.Text.Tests/DateTimeOffsetAndTimeSpanTests.cs @@ -59,6 +59,26 @@ public void Can_serialize_TimeSpan_field() Serialize(model); } + [Test] + public void Can_serialize_negative_TimeSpan_field() + { + var period = new TimeSpan(0, 0, -15, 0); + + var model = new SampleModel { Id = 1, TimeSpan = period }; + var json = JsonSerializer.SerializeToString(model); + Assert.That(json, Is.StringContaining("\"TimeSpan\":\"-PT15M\"")); + } + + [Test] + public void Can_deserialize_negative_TimeSpan_string() + { + var expectedTimeSpan = new TimeSpan(0, 0, -15, 0); + const string timeSpanString = @"-PT15M"; + + var timeSpan = JsonSerializer.DeserializeFromString(timeSpanString); + Assert.That(timeSpan, Is.EqualTo(expectedTimeSpan)); + } + [Test] public void Can_serialize_TimeSpan_field_with_StandardTimeSpanFormat() {