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

Commit bce8dcc

Browse files
committed
2 parents f13c48f + 8d51675 commit bce8dcc

File tree

3 files changed

+37
-22
lines changed

3 files changed

+37
-22
lines changed

src/ServiceStack.Text/Common/DateTimeSerializer.cs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public static class DateTimeSerializer
4545
private const char XsdTimeSeparator = 'T';
4646
private static readonly int XsdTimeSeparatorIndex = XsdDateTimeFormat.IndexOf(XsdTimeSeparator);
4747
private const string XsdUtcSuffix = "Z";
48-
private static readonly char[] DateTimeSeperators = new[] { '-', '/' };
48+
private static readonly char[] DateTimeSeparators = { '-', '/' };
4949
private static readonly Regex UtcOffsetInfoRegex = new Regex("([+-](?:2[0-3]|[0-1][0-9]):[0-5][0-9])", PclExport.Instance.RegexOptions);
5050
public static Func<string, Exception, DateTime> OnParseErrorFn { get; set; }
5151

@@ -100,7 +100,8 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr)
100100
return unspecifiedDate.Prepare();
101101
}
102102

103-
if (dateTimeStr.Length == DefaultDateTimeFormatWithFraction.Length)
103+
var hasUtcSuffix = dateTimeStr.EndsWith(XsdUtcSuffix);
104+
if (!hasUtcSuffix && dateTimeStr.Length == DefaultDateTimeFormatWithFraction.Length)
104105
{
105106
var unspecifiedDate = config.AssumeUtc
106107
? DateTime.Parse(dateTimeStr, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal)
@@ -109,7 +110,9 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr)
109110
return unspecifiedDate.Prepare();
110111
}
111112

112-
var kind = DateTimeKind.Unspecified;
113+
var kind = hasUtcSuffix
114+
? DateTimeKind.Utc
115+
: DateTimeKind.Unspecified;
113116
switch (config.DateHandler)
114117
{
115118
case DateHandler.UnixTime:
@@ -135,7 +138,7 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr)
135138

136139
if (dateTimeStr.Length >= XsdDateTimeFormat3F.Length
137140
&& dateTimeStr.Length <= XsdDateTimeFormat.Length
138-
&& dateTimeStr.EndsWith(XsdUtcSuffix))
141+
&& hasUtcSuffix)
139142
{
140143
var dateTime = Env.IsMono ? ParseManual(dateTimeStr) : null;
141144
if (dateTime != null)
@@ -144,7 +147,7 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr)
144147
return PclExport.Instance.ParseXsdDateTimeAsUtc(dateTimeStr);
145148
}
146149

147-
if (dateTimeStr.Length == CondensedDateTimeFormat.Length && dateTimeStr.IndexOfAny(DateTimeSeperators) == -1)
150+
if (dateTimeStr.Length == CondensedDateTimeFormat.Length && dateTimeStr.IndexOfAny(DateTimeSeparators) == -1)
148151
{
149152
return DateTime.ParseExact(dateTimeStr, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None);
150153
}
@@ -164,12 +167,14 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr)
164167
{
165168
if (config.SkipDateTimeConversion)
166169
{
167-
return DateTime.Parse(dateTimeStr, null,
168-
kind == DateTimeKind.Unspecified
169-
? DateTimeStyles.None
170-
: kind == DateTimeKind.Local
171-
? DateTimeStyles.AssumeLocal
172-
: DateTimeStyles.AssumeUniversal);
170+
var dateTimeStyle = kind == DateTimeKind.Unspecified
171+
? DateTimeStyles.None
172+
: kind == DateTimeKind.Local
173+
? DateTimeStyles.AssumeLocal
174+
: DateTimeStyles.AssumeUniversal;
175+
if (config.AlwaysUseUtc)
176+
dateTimeStyle |= DateTimeStyles.AdjustToUniversal;
177+
return DateTime.Parse(dateTimeStr, null, dateTimeStyle);
173178
}
174179

175180
var assumeKind = config.AssumeUtc ? DateTimeStyles.AssumeUniversal : DateTimeStyles.AssumeLocal;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ public void Can_deserialize_json_date_iso8601_with_skipDateTimeConversion_true()
452452

453453
using (JsConfig.With(new Config { AlwaysUseUtc = true }))
454454
{
455-
Assert.AreEqual(DateTimeKind.Local, JsonSerializer.DeserializeFromString<Utils.DateTimeISO8601Tests.TestObject>(JsonSerializer.SerializeToString<Utils.DateTimeISO8601Tests.TestObject>(testObject)).Date.Kind);
455+
Assert.AreEqual(DateTimeKind.Utc, JsonSerializer.DeserializeFromString<Utils.DateTimeISO8601Tests.TestObject>(JsonSerializer.SerializeToString<Utils.DateTimeISO8601Tests.TestObject>(testObject)).Date.Kind);
456456
}
457457
using (JsConfig.With(new Config { AlwaysUseUtc = true, SkipDateTimeConversion = false }))
458458
{

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ public void DateTimeKind_Does_Not_Change_With_SkipDateTimeConversion_true()
443443

444444
using (JsConfig.With(new Config { AlwaysUseUtc = true }))
445445
{
446-
Assert.AreEqual(DateTimeKind.Local, TypeSerializer.DeserializeFromString<TestObject>(TypeSerializer.SerializeToString<TestObject>(testObject)).Date.Kind);
446+
Assert.AreEqual(DateTimeKind.Utc, TypeSerializer.DeserializeFromString<TestObject>(TypeSerializer.SerializeToString<TestObject>(testObject)).Date.Kind);
447447
}
448448
using (JsConfig.With(new Config { AlwaysUseUtc = true, SkipDateTimeConversion = false }))
449449
{
@@ -776,23 +776,33 @@ public void Does_not_lose_precision()
776776
}
777777

778778
[TestFixture]
779-
public class UnixTimeScopeTests
779+
public class ScopedDateTimeTests
780780
{
781781
[Test]
782782
public void Does_serialize_to_UnixTime_when_scoped()
783783
{
784784
var dto = new TestObject { Date = new DateTime(2001, 01, 01, 0, 0, 0, DateTimeKind.Utc) };
785785

786-
using (var config = JsConfig.BeginScope())
787-
{
788-
config.DateHandler = DateHandler.UnixTime;
786+
using var config = JsConfig.With(new Config { DateHandler = DateHandler.UnixTime });
787+
var json = dto.ToJson();
788+
Assert.That(json, Is.EquivalentTo("{\"Date\":978307200}"));
789789

790-
var json = dto.ToJson();
791-
Assert.That(json, Is.EquivalentTo("{\"Date\":978307200}"));
790+
var fromJson = JsonSerializer.DeserializeFromString<TestObject>(json);
791+
Assert.That(fromJson.Date, Is.EqualTo(dto.Date));
792+
}
792793

793-
var fromJson = JsonSerializer.DeserializeFromString<TestObject>(json);
794-
Assert.That(fromJson.Date, Is.EqualTo(dto.Date));
795-
}
794+
[Test]
795+
[TestCase("2020-08-07T09:36:20.960Z")]
796+
[TestCase("2020-08-07T09:36:20.96Z")]
797+
[TestCase("2020-08-07T09:36:20.9Z")]
798+
[TestCase("2020-08-07T09:36:20Z")]
799+
public void Does_preserve_UTC_timezone_with_all_fractions(string dateFmt)
800+
{
801+
using var scope = JsConfig.CreateScope("AssumeUtc:false,AlwaysUseUtc:true,SkipDateTimeConversion:true");
802+
var date = JsonSerializer.DeserializeFromString<DateTime>(dateFmt);
803+
Assert.That(date.Kind, Is.EqualTo(DateTimeKind.Utc));
804+
Assert.That(date, Is.EqualTo(new DateTime(2020, 08, 07, 9, 36, 20))
805+
.Within(TimeSpan.FromSeconds(1)));
796806
}
797807
}
798808
}

0 commit comments

Comments
 (0)