Skip to content

Commit da80c48

Browse files
DemisDemis
authored andcommitted
Add ParseManual workaround for parsing Dates in Mono
1 parent c89a3fe commit da80c48

3 files changed

Lines changed: 111 additions & 7 deletions

File tree

src/ServiceStack.Text/Common/DateTimeSerializer.cs

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr)
6969
}
7070

7171
if (dateTimeStr.Length == XsdDateTimeFormatSeconds.Length)
72-
return DateTime.ParseExact(dateTimeStr, XsdDateTimeFormatSeconds, null,
73-
DateTimeStyles.AdjustToUniversal);
72+
return DateTime.ParseExact(dateTimeStr, XsdDateTimeFormatSeconds, null, DateTimeStyles.AdjustToUniversal);
7473

7574
if (dateTimeStr.Length >= XsdDateTimeFormat3F.Length
7675
&& dateTimeStr.Length <= XsdDateTimeFormat.Length
@@ -79,15 +78,119 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr)
7978
#if NETFX_CORE
8079
var dateTimeType = JsConfig.DateHandler != JsonDateHandler.ISO8601
8180
? "yyyy-MM-ddTHH:mm:sszzzzzzz"
82-
: "yyyy-MM-ddTHH:mm:sszzzzzzz";
81+
: "yyyy-MM-ddTHH:mm:sszzzzzzz";
8382

8483
return XmlConvert.ToDateTimeOffset(dateTimeStr, dateTimeType).DateTime.Prepare();
8584
#else
85+
var dateTime = Env.IsMono ? ParseManual(dateTimeStr) : null;
86+
if (dateTime != null)
87+
return dateTime.Value;
88+
8689
return XmlConvert.ToDateTime(dateTimeStr, XmlDateTimeSerializationMode.Utc).Prepare();
8790
#endif
8891
}
8992

90-
return DateTime.Parse(dateTimeStr, null, DateTimeStyles.AssumeLocal).Prepare();
93+
try
94+
{
95+
return DateTime.Parse(dateTimeStr, null, DateTimeStyles.AssumeLocal).Prepare();
96+
}
97+
catch(FormatException)
98+
{
99+
var manualDate = ParseManual(dateTimeStr);
100+
if (manualDate != null)
101+
return manualDate.Value;
102+
103+
throw;
104+
}
105+
}
106+
107+
public static DateTime? ParseManual(string dateTimeStr)
108+
{
109+
if (dateTimeStr == null || dateTimeStr.Length < "YYYY-MM-DD".Length)
110+
return null;
111+
112+
var dateKind = DateTimeKind.Utc;
113+
if (dateTimeStr.EndsWith("Z"))
114+
{
115+
dateTimeStr = dateTimeStr.Substring(0, dateTimeStr.Length - 1);
116+
}
117+
118+
var parts = dateTimeStr.Split('T');
119+
if (parts.Length == 1)
120+
parts = dateTimeStr.SplitOnFirst(' ');
121+
122+
var dateParts = parts[0].Split('-');
123+
int hh = 0, min = 0, ss = 0, ms = 0;
124+
double subMs = 0;
125+
int offsetMultiplier = 0;
126+
127+
if (parts.Length == 2)
128+
{
129+
var timeStringParts = parts[1].Split('+');
130+
if (timeStringParts.Length == 2)
131+
{
132+
offsetMultiplier = -1;
133+
}
134+
else
135+
{
136+
timeStringParts = parts[1].Split('-');
137+
if (timeStringParts.Length == 2)
138+
{
139+
offsetMultiplier = 1;
140+
}
141+
}
142+
143+
var timeOffset = timeStringParts.Length == 2 ? timeStringParts[1] : null;
144+
var timeParts = timeStringParts[0].Split(':');
145+
146+
if (timeParts.Length == 3)
147+
{
148+
int.TryParse(timeParts[0], out hh);
149+
int.TryParse(timeParts[1], out min);
150+
151+
var secParts = timeParts[2].Split('.');
152+
int.TryParse(secParts[0], out ss);
153+
if (secParts.Length == 2)
154+
{
155+
var msStr = secParts[1].PadRight(3, '0');
156+
ms = int.Parse(msStr.Substring(0, 3));
157+
158+
if (msStr.Length > 3)
159+
{
160+
var subMsStr = msStr.Substring(3);
161+
subMs = double.Parse(subMsStr) / Math.Pow(10, subMsStr.Length);
162+
}
163+
}
164+
}
165+
166+
var dateTime = new DateTime(int.Parse(dateParts[0]), int.Parse(dateParts[1]), int.Parse(dateParts[2]), hh, min, ss, ms, dateKind);
167+
if (subMs != 0)
168+
{
169+
dateTime.AddMilliseconds(subMs);
170+
}
171+
172+
if (offsetMultiplier != 0 && timeOffset != null)
173+
{
174+
timeParts = timeOffset.Split(':');
175+
if (timeParts.Length == 2)
176+
{
177+
hh = int.Parse(timeParts[0]);
178+
min = int.Parse(timeParts[1]);
179+
}
180+
else
181+
{
182+
hh = int.Parse(timeOffset.Substring(0,2));
183+
min = int.Parse(timeOffset.Substring(2));
184+
}
185+
186+
dateTime = dateTime.AddHours(offsetMultiplier * hh);
187+
dateTime = dateTime.AddMinutes(offsetMultiplier * min);
188+
}
189+
190+
return dateTime.ToLocalTime().Prepare();
191+
}
192+
193+
return null;
91194
}
92195

93196
public static string ToDateTimeString(DateTime dateTime)

tests/ServiceStack.Text.Tests/JsonTests/JsonDateTimeTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ public class JsonDateTimeTests
1414
[SetUp]
1515
public void SetUp()
1616
{
17+
JsConfig.Reset();
1718
_localTimezoneOffset = TimeZoneInfo.Local.BaseUtcOffset.Hours.ToString("00") + TimeZoneInfo.Local.BaseUtcOffset.Minutes.ToString("00");
18-
1919
}
2020

2121
#region TimestampOffset Tests
@@ -231,6 +231,7 @@ public void Can_deserialize_json_date_dcjsCompatible_unspecified()
231231
[Test]
232232
public void When_using_ISO8601_and_serializing_as_Utc_It_should_deserialize_as_Utc()
233233
{
234+
JsConfig.AlwaysUseUtc = true;
234235
JsConfig.DateHandler = JsonDateHandler.ISO8601;
235236
var initialDate = new DateTime(2012, 7, 25, 16, 17, 00, DateTimeKind.Utc);
236237
var json = JsonSerializer.SerializeToString(initialDate); //"2012-07-25T16:17:00.0000000Z"

tests/ServiceStack.Text.Tests/Utils/DateTimeSerializerTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ public void AssertDateIsEqual(int whichDate)
194194
shortDateTimeUtc.Hour, shortDateTimeUtc.Minute, shortDateTimeUtc.Second,
195195
shortDateTimeUtc.Millisecond, DateTimeKind.Utc)));
196196

197-
Assert.That(longDateTime.ToStableUniversalTime(), Is.EqualTo(dateTime.ToStableUniversalTime()));
197+
AssertDatesAreEqual(longDateTime.ToStableUniversalTime(), dateTime.ToStableUniversalTime());
198198

199199
var toDateTime = DateTimeSerializer.ParseShortestXsdDateTime(shortestDateStr);
200200
AssertDatesAreEqual(toDateTime, dateTime, "shortestDate");
@@ -208,7 +208,7 @@ public void AssertDateIsEqual(int whichDate)
208208
AssertDatesAreEqual(wcfDate, dateTime, "wcf date");
209209
}
210210

211-
private void AssertDatesAreEqual(DateTime toDateTime, DateTime dateTime, string which)
211+
private void AssertDatesAreEqual(DateTime toDateTime, DateTime dateTime, string which=null)
212212
{
213213
Assert.That(toDateTime.ToStableUniversalTime().RoundToMs(), Is.EqualTo(dateTime.ToStableUniversalTime().RoundToMs()), which);
214214
}

0 commit comments

Comments
 (0)