Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit a217ee6

Browse files
committed
Add support for System.Xml dependency-free XSD TimeSpan Converter
1 parent 57e88f2 commit a217ee6

File tree

7 files changed

+157
-0
lines changed

7 files changed

+157
-0
lines changed

src/ServiceStack.Text/ServiceStack.Text.PCL.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@
225225
<Compile Include="Support\DoubleConverter.cs">
226226
<SubType>Code</SubType>
227227
</Compile>
228+
<Compile Include="Support\TimeSpanConverter.cs" />
228229
<Compile Include="Support\TypePair.cs">
229230
<SubType>Code</SubType>
230231
</Compile>

src/ServiceStack.Text/ServiceStack.Text.SL5.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@
248248
<Compile Include="Support\DoubleConverter.cs">
249249
<SubType>Code</SubType>
250250
</Compile>
251+
<Compile Include="Support\TimeSpanConverter.cs" />
251252
<Compile Include="Support\TypePair.cs">
252253
<SubType>Code</SubType>
253254
</Compile>

src/ServiceStack.Text/ServiceStack.Text.Signed.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@
280280
<Compile Include="Support\DoubleConverter.cs">
281281
<SubType>Code</SubType>
282282
</Compile>
283+
<Compile Include="Support\TimeSpanConverter.cs" />
283284
<Compile Include="Support\TypePair.cs">
284285
<SubType>Code</SubType>
285286
</Compile>

src/ServiceStack.Text/ServiceStack.Text.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@
274274
<Compile Include="Support\DoubleConverter.cs">
275275
<SubType>Code</SubType>
276276
</Compile>
277+
<Compile Include="Support\TimeSpanConverter.cs" />
277278
<Compile Include="Support\TypePair.cs">
278279
<SubType>Code</SubType>
279280
</Compile>
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using System.Linq;
5+
using System.Text;
6+
7+
namespace ServiceStack.Text.Support
8+
{
9+
public class TimeSpanConverter
10+
{
11+
public static string ToXsdDuration(TimeSpan timeSpan)
12+
{
13+
var sb = new StringBuilder("P");
14+
15+
double d = timeSpan.TotalSeconds;
16+
17+
int totalSeconds = (int)(d);
18+
int remainingMs = (int)(Math.Round(d - totalSeconds, 3) * 1000);
19+
int sec = (totalSeconds >= 60 ? totalSeconds % 60 : totalSeconds);
20+
int min = (totalSeconds = (totalSeconds / 60)) >= 60 ? totalSeconds % 60 : totalSeconds;
21+
int hours = (totalSeconds = (totalSeconds / 60)) >= 24 ? totalSeconds % 24 : totalSeconds;
22+
int days = (totalSeconds = (totalSeconds / 24)) >= 30 ? totalSeconds % 30 : totalSeconds;
23+
24+
if (days > 0)
25+
{
26+
sb.Append(days + "D");
27+
}
28+
29+
if (hours + min + sec + remainingMs > 0)
30+
{
31+
sb.Append("T");
32+
if (hours > 0)
33+
{
34+
sb.Append(hours + "H");
35+
}
36+
if (min > 0)
37+
{
38+
sb.Append(min + "M");
39+
}
40+
41+
42+
if (remainingMs > 0)
43+
{
44+
sb.Append(sec + "." + remainingMs.ToString(CultureInfo.InvariantCulture).PadLeft(3, '0') + "S");
45+
}
46+
else if (sec > 0)
47+
{
48+
sb.Append(sec + "S");
49+
}
50+
}
51+
52+
var xsdDuration = sb.ToString();
53+
return xsdDuration;
54+
}
55+
56+
public static TimeSpan FromXsdDuration(string xsdDuration)
57+
{
58+
int days = 0;
59+
int hours = 0;
60+
int minutes = 0;
61+
int seconds = 0;
62+
double ms = 0.0;
63+
64+
string[] t = xsdDuration.Substring(1).SplitOnFirst('T'); //strip P
65+
66+
var hasTime = t.Length == 2;
67+
68+
string[] d = t[0].SplitOnFirst('D');
69+
if (d.Length == 2)
70+
{
71+
int day;
72+
if (int.TryParse(d[0], out day))
73+
days = day;
74+
}
75+
76+
if (hasTime)
77+
{
78+
string[] h = t[1].SplitOnFirst('H');
79+
if (h.Length == 2)
80+
{
81+
int hour;
82+
if (int.TryParse(h[0], out hour))
83+
hours = hour;
84+
}
85+
86+
string[] m = h[h.Length - 1].SplitOnFirst('M');
87+
if (m.Length == 2)
88+
{
89+
int min;
90+
if (int.TryParse(m[0], out min))
91+
minutes = min;
92+
}
93+
94+
string[] s = m[m.Length - 1].SplitOnFirst('S');
95+
if (s.Length == 2)
96+
{
97+
double millis;
98+
if (double.TryParse(s[0], out millis))
99+
ms = millis;
100+
}
101+
102+
seconds = (int)ms;
103+
ms -= seconds;
104+
}
105+
106+
double totalSecs = 0
107+
+ (days * 24 * 60 * 60)
108+
+ (hours * 60 * 60)
109+
+ (minutes * 60)
110+
+ (seconds);
111+
112+
double interval = totalSecs + ms;
113+
114+
return TimeSpan.FromSeconds(interval);
115+
}
116+
}
117+
}

tests/ServiceStack.Text.Tests/ServiceStack.Text.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@
291291
<Compile Include="Support\BenchmarkTests.cs" />
292292
<Compile Include="Support\MovieDtos.cs" />
293293
<Compile Include="SystemTimeTests.cs" />
294+
<Compile Include="TimeSpanConverterTests.cs" />
294295
<Compile Include="TupleTests.cs" />
295296
<Compile Include="UseCases\CentroidTests.cs" />
296297
<Compile Include="UseCases\GitHubRestTests.cs" />
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using NUnit.Framework;
6+
using ServiceStack.Text.Support;
7+
8+
namespace ServiceStack.Text.Tests
9+
{
10+
[TestFixture]
11+
public class TimeSpanConverterTests
12+
{
13+
[Test]
14+
public void Can_Serialize_TimeSpan()
15+
{
16+
Assert.That(TimeSpanConverter.ToXsdDuration(new TimeSpan(1, 0, 0, 0)), Is.EqualTo("P1D"));
17+
Assert.That(TimeSpanConverter.ToXsdDuration(new TimeSpan(1, 0, 0)), Is.EqualTo("PT1H"));
18+
Assert.That(TimeSpanConverter.ToXsdDuration(new TimeSpan(0, 1, 0)), Is.EqualTo("PT1M"));
19+
Assert.That(TimeSpanConverter.ToXsdDuration(new TimeSpan(0, 0, 1)), Is.EqualTo("PT1S"));
20+
Assert.That(TimeSpanConverter.ToXsdDuration(new TimeSpan(0, 0, 0, 0, 1)), Is.EqualTo("PT0.001S"));
21+
Assert.That(TimeSpanConverter.ToXsdDuration(new TimeSpan(1, 1, 1, 1, 1)), Is.EqualTo("P1DT1H1M1.001S"));
22+
}
23+
24+
[Test]
25+
public void Can_deserialize_TimeSpan()
26+
{
27+
Assert.That(TimeSpanConverter.FromXsdDuration("P1D"), Is.EqualTo(new TimeSpan(1, 0, 0, 0)));
28+
Assert.That(TimeSpanConverter.FromXsdDuration("PT1H"), Is.EqualTo(new TimeSpan(1, 0, 0)));
29+
Assert.That(TimeSpanConverter.FromXsdDuration("PT1M"), Is.EqualTo(new TimeSpan(0, 1, 0)));
30+
Assert.That(TimeSpanConverter.FromXsdDuration("PT1S"), Is.EqualTo(new TimeSpan(0, 0, 1)));
31+
Assert.That(TimeSpanConverter.FromXsdDuration("PT0.001S"), Is.EqualTo(new TimeSpan(0, 0, 0, 0, 1)));
32+
Assert.That(TimeSpanConverter.FromXsdDuration("P1DT1H1M1.001S"), Is.EqualTo(new TimeSpan(1, 1, 1, 1, 1)));
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)