From 18abe785504e933e3f7b78ed7684f11d8f769f42 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Tue, 27 Aug 2019 15:01:09 -0400 Subject: [PATCH] feat: Better handling of JSON DateTimes in Net Standard --- CHANGELOG.md | 1 + ICD.Common.Utils.Tests/Json/JsonUtilsTest.cs | 24 +------- .../Extensions/JsonReaderExtensions.cs | 50 +++++++++++++--- ICD.Common.Utils/Json/JsonUtils.cs | 58 ------------------- 4 files changed, 44 insertions(+), 89 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30921a0..c1f1d7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed - Fixed a bug where ANSI color encoded strings with percentages were being scrambled + - Improvements to JSON DateTime parsing, particularly in Net Standard ## [9.7.0] - 2019-08-15 ### Added diff --git a/ICD.Common.Utils.Tests/Json/JsonUtilsTest.cs b/ICD.Common.Utils.Tests/Json/JsonUtilsTest.cs index 0eae21e..b257c8d 100644 --- a/ICD.Common.Utils.Tests/Json/JsonUtilsTest.cs +++ b/ICD.Common.Utils.Tests/Json/JsonUtilsTest.cs @@ -10,29 +10,7 @@ namespace ICD.Common.Utils.Tests.Json public sealed class JsonUtilsTest { [Test] - public void CacheTypeTest() - { - Assert.Inconclusive(); - } - - [Test] - public void ParseDateTimeTest() - { - const string dataA = "2016-02-26T19:24:59"; - const string dataB = "2019-04-01T12:41:15-04:00"; - - Assert.DoesNotThrow(() => JsonUtils.ParseDateTime(dataA)); - Assert.DoesNotThrow(() => JsonUtils.ParseDateTime(dataB)); - } - - [Test] - public void TryParseDateTimeTest() - { - Assert.Inconclusive(); - } - - [Test] - public void PrintTest() + public void FormatTest() { Assert.Inconclusive(); } diff --git a/ICD.Common.Utils/Extensions/JsonReaderExtensions.cs b/ICD.Common.Utils/Extensions/JsonReaderExtensions.cs index 808b25c..263e616 100644 --- a/ICD.Common.Utils/Extensions/JsonReaderExtensions.cs +++ b/ICD.Common.Utils/Extensions/JsonReaderExtensions.cs @@ -1,6 +1,5 @@ using System; using ICD.Common.Properties; -using ICD.Common.Utils.Json; using Newtonsoft.Json; namespace ICD.Common.Utils.Extensions @@ -21,7 +20,12 @@ namespace ICD.Common.Utils.Extensions if (extends == null) throw new ArgumentNullException("extends"); - JsonSerializer serializer = new JsonSerializer(); + JsonSerializer serializer = +#if SIMPLSHARP + new JsonSerializer(); +#else + JsonSerializer.CreateDefault(); +#endif return extends.ReadAsObject(serializer); } @@ -145,7 +149,13 @@ namespace ICD.Common.Utils.Extensions { if (extends == null) throw new ArgumentNullException("extends"); - + +#if !SIMPLSHARP + // Newer versions of NewtonSoft try to be helpful and interpret strings as DateTimes without any consideration for different DateTime formats. + if (extends.TokenType == JsonToken.Date && extends.DateParseHandling != DateParseHandling.None) + throw new InvalidOperationException("DateParseHandling needs to be set to None"); +#endif + if (!extends.TokenType.IsPrimitive()) throw new FormatException("Expected primitive token type but got " + extends.TokenType); @@ -213,12 +223,36 @@ namespace ICD.Common.Utils.Extensions if (extends == null) throw new ArgumentNullException("extends"); -#if SIMPLSHARP - string stringValue = extends.GetValueAsString(); - return JsonUtils.ParseDateTime(stringValue); -#else - return (DateTime)extends.Value; +#if !SIMPLSHARP + // Newer NewtonSoft tries to be helpful by assuming that anything that looks like a DateTime must be a date. + if (extends.DateParseHandling != DateParseHandling.None) + return (DateTime)extends.Value; #endif + + string stringValue = extends.GetValueAsString(); + return DateTime.Parse(stringValue); + } + + /// + /// Gets the current value as a date. + /// + /// + /// + /// + /// + public static DateTime GetValueAsDateTimeExact(this JsonReader extends, string format, IFormatProvider provider) + { + if (extends == null) + throw new ArgumentNullException("extends"); + +#if !SIMPLSHARP + // Newer NewtonSoft tries to be helpful by assuming that anything that looks like a DateTime must be a date. + if (extends.DateParseHandling != DateParseHandling.None) + throw new InvalidOperationException("DateParseHandling needs to be set to None"); +#endif + + string stringValue = extends.GetValueAsString(); + return DateTime.ParseExact(stringValue, format, provider); } } } diff --git a/ICD.Common.Utils/Json/JsonUtils.cs b/ICD.Common.Utils/Json/JsonUtils.cs index 73e7140..4051688 100644 --- a/ICD.Common.Utils/Json/JsonUtils.cs +++ b/ICD.Common.Utils/Json/JsonUtils.cs @@ -5,7 +5,6 @@ using ICD.Common.Properties; using ICD.Common.Utils.Extensions; using ICD.Common.Utils.IO; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace ICD.Common.Utils.Json { @@ -18,63 +17,6 @@ namespace ICD.Common.Utils.Json private const string MESSAGE_NAME_PROPERTY = "m"; private const string MESSAGE_DATA_PROPERTY = "d"; - /// - /// Gets the data as a DateTime value. - /// - /// - /// - public static DateTime ParseDateTime(string data) - { - return DateTime.Parse(data); - } - - /// - /// Gets the token as a DateTime value. - /// - /// - /// - [PublicAPI] - public static DateTime ParseDateTime(JToken token) - { - if (token == null) - throw new ArgumentNullException("token"); - -#if SIMPLSHARP - return ParseDateTime((string)token); -#else - return (DateTime)token; -#endif - } - - /// - /// Gets the token as a DateTime value. - /// - /// - /// - /// - [PublicAPI] - public static bool TryParseDateTime(JToken token, out DateTime output) - { - if (token == null) - throw new ArgumentNullException("token"); - - output = default(DateTime); - - try - { - output = ParseDateTime(token); - return true; - } - catch (FormatException) - { - return false; - } - catch (InvalidCastException) - { - return false; - } - } - /// /// Serializes the given item and formats the JSON into a human-readable form. ///