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

Commit e0b9860

Browse files
committed
Fix Min/Max DateTimeOffset/TimeSpan precision issues
1 parent 112e7d5 commit e0b9860

File tree

4 files changed

+88
-26
lines changed

4 files changed

+88
-26
lines changed

src/ServiceStack.Text/Common/DateTimeSerializer.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,13 +487,21 @@ public static string ToShortestXsdDateTimeString(DateTime dateTime)
487487

488488
static readonly char[] TimeZoneChars = new[] { '+', '-' };
489489

490+
private const string MinDateTimeOffsetWcfValue = "\\/Date(-62135596800000)\\/";
491+
private const string MaxDateTimeOffsetWcfValue = "\\/Date(253402300799999)\\/";
492+
490493
/// <summary>
491494
/// WCF Json format: /Date(unixts+0000)/
492495
/// </summary>
493496
/// <param name="wcfJsonDate"></param>
494497
/// <returns></returns>
495498
public static DateTimeOffset ParseWcfJsonDateOffset(string wcfJsonDate)
496499
{
500+
if (wcfJsonDate == MinDateTimeOffsetWcfValue)
501+
return DateTimeOffset.MinValue;
502+
if (wcfJsonDate == MaxDateTimeOffsetWcfValue)
503+
return DateTimeOffset.MaxValue;
504+
497505
if (wcfJsonDate[0] == '\\')
498506
{
499507
wcfJsonDate = wcfJsonDate.Substring(1);
@@ -655,7 +663,7 @@ public static string ToWcfJsonDate(DateTime dateTime)
655663
return StringBuilderThreadStatic.ReturnAndFree(sb);
656664
}
657665
}
658-
666+
659667
public static void WriteWcfJsonDateTimeOffset(TextWriter writer, DateTimeOffset dateTimeOffset)
660668
{
661669
if (JsConfig.DateHandler == DateHandler.ISO8601)

src/ServiceStack.Text/Support/TimeSpanConverter.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,24 @@ namespace ServiceStack.Text.Support
66
{
77
public class TimeSpanConverter
88
{
9+
private const string MinSerializedValue = "-P10675199DT2H48M5.4775391S";
10+
private const string MaxSerializedValue = "P10675199DT2H48M5.4775391S";
11+
912
public static string ToXsdDuration(TimeSpan timeSpan)
1013
{
14+
if (timeSpan == TimeSpan.MinValue)
15+
return MinSerializedValue;
16+
if (timeSpan == TimeSpan.MaxValue)
17+
return MaxSerializedValue;
18+
1119
var sb = StringBuilderThreadStatic.Allocate();
1220

1321
sb.Append(timeSpan.Ticks < 0 ? "-P" : "P");
1422

15-
double ticks = timeSpan.Ticks > 0 ? timeSpan.Ticks : timeSpan.Ticks * -1L;
23+
double ticks = timeSpan.Ticks;
24+
if (ticks < 0)
25+
ticks = -ticks;
26+
1627
double totalSeconds = ticks / TimeSpan.TicksPerSecond;
1728
long wholeSeconds = (long) totalSeconds;
1829
long seconds = wholeSeconds;
@@ -51,6 +62,11 @@ public static string ToXsdDuration(TimeSpan timeSpan)
5162

5263
public static TimeSpan FromXsdDuration(string xsdDuration)
5364
{
65+
if (xsdDuration == MinSerializedValue)
66+
return TimeSpan.MinValue;
67+
if (xsdDuration == MaxSerializedValue)
68+
return TimeSpan.MaxValue;
69+
5470
long days = 0;
5571
long hours = 0;
5672
long minutes = 0;
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
using NUnit.Framework;
3+
4+
namespace ServiceStack.Text.Tests.Issues
5+
{
6+
public class SerializationPrecisionIssues
7+
{
8+
public class TimeSpanWrapper
9+
{
10+
public TimeSpan TimeSpan { get; set; }
11+
}
12+
13+
[Test]
14+
public void Can_convert_min_TimeSpan()
15+
{
16+
var dto = new TimeSpanWrapper {
17+
TimeSpan = TimeSpan.MinValue,
18+
};
19+
var json = JsonSerializer.SerializeToString(dto, typeof(TimeSpanWrapper));
20+
var fromJson = JsonSerializer.DeserializeFromString<TimeSpanWrapper>(json);
21+
Assert.That(fromJson.TimeSpan, Is.EqualTo(dto.TimeSpan));
22+
}
23+
24+
[Test]
25+
public void Can_convert_max_TimeSpan()
26+
{
27+
var dto = new TimeSpanWrapper {
28+
TimeSpan = TimeSpan.MaxValue,
29+
};
30+
var json = JsonSerializer.SerializeToString(dto, typeof(TimeSpanWrapper));
31+
var fromJson = JsonSerializer.DeserializeFromString<TimeSpanWrapper>(json);
32+
Assert.That(fromJson.TimeSpan, Is.EqualTo(dto.TimeSpan));
33+
}
34+
35+
class DateTimeOffsetWrapper
36+
{
37+
public DateTimeOffset DateTimeOffset { get; set; }
38+
}
39+
40+
[Test]
41+
public void Can_convert_min_DateTimeOffset()
42+
{
43+
var dto = new DateTimeOffsetWrapper {
44+
DateTimeOffset = DateTimeOffset.MinValue,
45+
};
46+
var json = JsonSerializer.SerializeToString(dto, typeof(DateTimeOffsetWrapper));
47+
var fromJson = JsonSerializer.DeserializeFromString<DateTimeOffsetWrapper>(json);
48+
Assert.That(fromJson.DateTimeOffset, Is.EqualTo(dto.DateTimeOffset));
49+
}
50+
51+
[Test]
52+
public void Can_convert_max_DateTimeOffset()
53+
{
54+
var dto = new DateTimeOffsetWrapper {
55+
DateTimeOffset = DateTimeOffset.MaxValue,
56+
};
57+
var json = JsonSerializer.SerializeToString(dto, typeof(DateTimeOffsetWrapper));
58+
var fromJson = JsonSerializer.DeserializeFromString<DateTimeOffsetWrapper>(json);
59+
Assert.That(fromJson.DateTimeOffset, Is.EqualTo(dto.DateTimeOffset));
60+
}
61+
}
62+
}

tests/ServiceStack.Text.Tests/Issues/StackOverflowIssues.cs

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)