From cae76f60c0b8f40f07540a392148dea6ff1df6fb Mon Sep 17 00:00:00 2001 From: mwelch Date: Mon, 23 Mar 2015 15:13:10 -0400 Subject: [PATCH 1/8] Changed so that DateTime serialization respects JsConfig.AssumeUtc flag and added unit tests to confirm --- .../Common/DateTimeSerializer.cs | 19 ++++++- .../Utils/DateTimeSerializerTests.cs | 55 +++++++++++++++++-- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/NServiceKit.Text/Common/DateTimeSerializer.cs b/src/NServiceKit.Text/Common/DateTimeSerializer.cs index f3c32a2..c81a2c6 100644 --- a/src/NServiceKit.Text/Common/DateTimeSerializer.cs +++ b/src/NServiceKit.Text/Common/DateTimeSerializer.cs @@ -73,18 +73,26 @@ public static class DateTimeSerializer /// The XSD UTC suffix. private const string XsdUtcSuffix = "Z"; - /// If AlwaysUseUtc is set to true then convert all DateTime to UTC. + /// + /// If AssumeUtc, assume DateTimeKind.Unspecified dates are really UTC. + /// If AlwaysUseUtc is set to true then convert all DateTime to UTC. + /// /// Date Time to be "Prepared". /// true to parsed as UTC. /// The Prepared DateTime. private static DateTime Prepare(this DateTime dateTime, bool parsedAsUtc = false) { + if (JsConfig.AssumeUtc && dateTime.Kind == DateTimeKind.Unspecified) + { + dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc); + } + if (JsConfig.AlwaysUseUtc) { return dateTime.Kind != DateTimeKind.Utc ? dateTime.ToStableUniversalTime() : dateTime; } - return parsedAsUtc ? dateTime.ToLocalTime() : dateTime; + return parsedAsUtc && !JsConfig.AssumeUtc ? dateTime.ToLocalTime() : dateTime; } /// Parses a date time string and returns a nullable datetime. @@ -155,7 +163,12 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr) try { - return DateTime.Parse(dateTimeStr, null, DateTimeStyles.AssumeLocal).Prepare(); + var parsed = DateTime.Parse(dateTimeStr, null, DateTimeStyles.AssumeLocal); + if (JsConfig.AssumeUtc) + { + parsed = DateTime.SpecifyKind(parsed, DateTimeKind.Utc); + } + return parsed.Prepare(parsedAsUtc: JsConfig.AssumeUtc); } catch (FormatException) { diff --git a/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs b/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs index 913a4fc..8ef993f 100644 --- a/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs +++ b/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs @@ -94,7 +94,7 @@ public void CanDeserializeDateTimeOffsetWithTimeSpanIsZero() } /// UTC local equals. - [Test][Ignore] + [Test, Ignore] public void Utc_Local_Equals() { var now = DateTime.Now; @@ -151,7 +151,8 @@ public void DateTimeWithoutMilliseconds_should_always_be_deserialized_correctly_ } /// UTC date time is deserialized as kind UTC. - [Test, Ignore("Don't pre-serialize into Utc")] + // [Test, Ignore("Don't pre-serialize into Utc")] + [Test] public void UtcDateTime_Is_Deserialized_As_Kind_Utc() { //Serializing UTC @@ -160,7 +161,7 @@ public void UtcDateTime_Is_Deserialized_As_Kind_Utc() var serialized = JsonSerializer.SerializeToString(utcNow); //Deserializing UTC? var deserialized = JsonSerializer.DeserializeFromString(serialized); - Assert.That(deserialized.Kind, Is.EqualTo(DateTimeKind.Utc)); //fails -> is DateTimeKind.Local + Assert.That(deserialized.Kind, Is.EqualTo(DateTimeKind.Utc)); } /// @@ -371,6 +372,52 @@ public void DateTime_Is_Serialized_As_Utc_and_Deserialized_as_local() { Assert.AreEqual(DateTimeKind.Utc, TypeSerializer.DeserializeFromString(TypeSerializer.SerializeToString(testObject)).Date.Kind); } - } + } + + /// + /// DateTime with DateTimeKind.Unspecified should be treated as UTC (rather than Local) when AssumeUtc is true + /// + [Test] + public void DateTime_Unspecified_Is_Serialized_And_Deserialized_As_Utc_When_AssumeUtc_Flag_Is_True() + { + var dateTimeUnspecified = new DateTime(2013, 1, 1, 0, 0, 1, DateTimeKind.Unspecified); + + // Using JsonSerializer becayse TypeSerializer doesn't call DateTimeSerializer.WriteWcfJsonDate + var deserialized = JsonSerializer.DeserializeFromString(JsonSerializer.SerializeToString(dateTimeUnspecified)); + Assert.AreEqual(DateTimeKind.Local, deserialized.Date.Kind); + Assert.AreEqual(dateTimeUnspecified.Hour, deserialized.Hour); + + + // Change the behavior with config + using (JsConfig.With(assumeUtc: true)) + { + // Using JsonSerializer becayse TypeSerializer doesn't call DateTimeSerializer.WriteWcfJsonDate + var serializedUtc = JsonSerializer.SerializeToString(dateTimeUnspecified); + var deserializedUtc = JsonSerializer.DeserializeFromString(serializedUtc); + Assert.AreEqual(DateTimeKind.Utc, deserializedUtc.Date.Kind); + Assert.AreEqual(dateTimeUnspecified.Hour, deserializedUtc.Hour); + } + } + + /// + /// Dates strings with no time component should deserialize to Midnight (00:00:00) Local by default, or Midnight Utc when AssumeUtc is set to true + /// + [Test] + public void DateTime_Should_Deserialize_Strings_With_No_Time_As_Midnight() + { + const string dateTimeStr = "2015-03-23"; + + var deserialized = (TypeSerializer.DeserializeFromString(dateTimeStr)); + Assert.AreEqual(DateTimeKind.Local, deserialized.Date.Kind); + Assert.AreEqual(0, deserialized.Hour); + + // Change the behavior with config + using (JsConfig.With(assumeUtc: true)) + { + var deserializedUtc = (TypeSerializer.DeserializeFromString(dateTimeStr)); + Assert.AreEqual(DateTimeKind.Utc, deserializedUtc.Date.Kind); + Assert.AreEqual(0, deserializedUtc.Hour); + } + } } } \ No newline at end of file From b18721a4ef79e6f225e1e94c56f7509e146513a1 Mon Sep 17 00:00:00 2001 From: mwelch Date: Mon, 23 Mar 2015 15:23:34 -0400 Subject: [PATCH 2/8] Cleaning up whitespace --- tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs b/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs index 8ef993f..c8f0eae 100644 --- a/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs +++ b/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs @@ -94,7 +94,7 @@ public void CanDeserializeDateTimeOffsetWithTimeSpanIsZero() } /// UTC local equals. - [Test, Ignore] + [Test][Ignore] public void Utc_Local_Equals() { var now = DateTime.Now; From 2aef06a941ed6678e1c3917f953abbeea9b8b729 Mon Sep 17 00:00:00 2001 From: mwelch Date: Mon, 23 Mar 2015 15:26:17 -0400 Subject: [PATCH 3/8] Fixed the whitespace for real this time :) --- .../NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs b/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs index c8f0eae..f5d6a9d 100644 --- a/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs +++ b/tests/NServiceKit.Text.Tests/Utils/DateTimeSerializerTests.cs @@ -150,9 +150,8 @@ public void DateTimeWithoutMilliseconds_should_always_be_deserialized_correctly_ Assert.AreEqual(dateWithoutMillisecondsUnspecified, deserialized); } - /// UTC date time is deserialized as kind UTC. - // [Test, Ignore("Don't pre-serialize into Utc")] - [Test] + /// UTC date time is deserialized as kind UTC. + [Test] public void UtcDateTime_Is_Deserialized_As_Kind_Utc() { //Serializing UTC From f75b7baf65b3615b8fda80a9498f0617e9e77913 Mon Sep 17 00:00:00 2001 From: mwelch Date: Thu, 26 Mar 2015 16:33:27 -0400 Subject: [PATCH 4/8] We found an issue... added another unit test to reproduce and fixed it --- .../Common/DateTimeSerializer.cs | 11 ++---- .../NServiceKit.Text.Tests.csproj | 22 ++++-------- .../Utils/DateTimeSerializerTests.cs | 36 +++++++++++++++++++ 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/src/NServiceKit.Text/Common/DateTimeSerializer.cs b/src/NServiceKit.Text/Common/DateTimeSerializer.cs index c81a2c6..18d9d4b 100644 --- a/src/NServiceKit.Text/Common/DateTimeSerializer.cs +++ b/src/NServiceKit.Text/Common/DateTimeSerializer.cs @@ -82,9 +82,9 @@ public static class DateTimeSerializer /// The Prepared DateTime. private static DateTime Prepare(this DateTime dateTime, bool parsedAsUtc = false) { - if (JsConfig.AssumeUtc && dateTime.Kind == DateTimeKind.Unspecified) + if (dateTime.Kind == DateTimeKind.Unspecified) { - dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc); + dateTime = DateTime.SpecifyKind(dateTime, JsConfig.AssumeUtc ? DateTimeKind.Utc : DateTimeKind.Local); } if (JsConfig.AlwaysUseUtc) @@ -163,12 +163,7 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr) try { - var parsed = DateTime.Parse(dateTimeStr, null, DateTimeStyles.AssumeLocal); - if (JsConfig.AssumeUtc) - { - parsed = DateTime.SpecifyKind(parsed, DateTimeKind.Utc); - } - return parsed.Prepare(parsedAsUtc: JsConfig.AssumeUtc); + return DateTime.Parse(dateTimeStr).Prepare(); } catch (FormatException) { diff --git a/tests/NServiceKit.Text.Tests/NServiceKit.Text.Tests.csproj b/tests/NServiceKit.Text.Tests/NServiceKit.Text.Tests.csproj index e337a2c..5b210ea 100644 --- a/tests/NServiceKit.Text.Tests/NServiceKit.Text.Tests.csproj +++ b/tests/NServiceKit.Text.Tests/NServiceKit.Text.Tests.csproj @@ -122,9 +122,6 @@ ..\..\lib\tests\NServiceKit.ServiceInterface.dll - - ..\..\src\NServiceKit.Text\bin\Release\NServiceKit.Text.dll - @@ -132,23 +129,10 @@ - - - - ..\..\lib\tests\nunit.framework.dll - - ..\..\lib\tests\Platform.dll - - - ..\..\lib\tests\protobuf-net.dll - - - ..\..\lib\tests\protobuf-net.Extensions.dll - @@ -265,6 +249,12 @@ + + + {579b3fdb-cdad-44e1-8417-885c38e49a0e} + NServiceKit.Text + +