From 0b975a2087f4ae21e6591a072f1948159c4a4b55 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Sun, 21 Jan 2018 12:16:48 +1300 Subject: [PATCH] -Cleaned up UnixDateTimeConverter --- .../Converters/UnixDateTimeConverterTests.cs | 33 ++++++-- .../Converters/UnixDateTimeConverter.cs | 82 +++++++++++-------- 2 files changed, 74 insertions(+), 41 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Converters/UnixDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/UnixDateTimeConverterTests.cs index 7d577046..a9b3cb87 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/UnixDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/UnixDateTimeConverterTests.cs @@ -33,6 +33,7 @@ using Assert = Newtonsoft.Json.Tests.XUnitAssert; using NUnit.Framework; #endif using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; using Newtonsoft.Json.Tests.TestObjects; namespace Newtonsoft.Json.Tests.Converters @@ -43,7 +44,7 @@ namespace Newtonsoft.Json.Tests.Converters [Test] public void SerializeDateTime() { - DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + DateTime unixEpoch = UnixDateTimeConverter.UnixEpoch; string result = JsonConvert.SerializeObject(unixEpoch, new UnixDateTimeConverter()); @@ -66,7 +67,18 @@ namespace Newtonsoft.Json.Tests.Converters { ExceptionAssert.Throws( () => JsonConvert.SerializeObject(new DateTime(1964, 2, 7), new UnixDateTimeConverter()), - "Expected a valid Unix date." + "Cannot convert date value that is before Unix epoch of 00:00:00 UTC on 1 January 1970." + ); + } + + [Test] + public void WriteJsonInvalidType() + { + UnixDateTimeConverter converter = new UnixDateTimeConverter(); + + ExceptionAssert.Throws( + () => converter.WriteJson(new JTokenWriter(), new object(), new JsonSerializer()), + "Expected date object value." ); } @@ -138,6 +150,15 @@ namespace Newtonsoft.Json.Tests.Converters Assert.AreEqual(new DateTimeOffset(2018, 1, 1, 21, 1, 16, TimeSpan.Zero), result); } + + [Test] + public void DeserializeInvalidStringToDateTimeOffset() + { + ExceptionAssert.Throws( + () => JsonConvert.DeserializeObject(@"""PIE""", new UnixDateTimeConverter()), + "Cannot convert invalid value to System.DateTimeOffset. Path '', line 1, position 5." + ); + } #endif [Test] @@ -159,18 +180,18 @@ namespace Newtonsoft.Json.Tests.Converters [Test] public void DeserializeInvalidValue() { - ExceptionAssert.Throws( + ExceptionAssert.Throws( () => JsonConvert.DeserializeObject("-1", new UnixDateTimeConverter()), - "Cannot convert invalid value -1 to System.DateTime. Path '', line 1, position 2." + "Cannot convert value that is before Unix epoch of 00:00:00 UTC on 1 January 1970 to System.DateTime. Path '', line 1, position 2." ); } [Test] public void DeserializeInvalidValueType() { - ExceptionAssert.Throws( + ExceptionAssert.Throws( () => JsonConvert.DeserializeObject("false", new UnixDateTimeConverter()), - "Cannot convert invalid value to System.DateTime. Path '', line 1, position 5." + "Unexpected token parsing date. Expected Integer or String, got Boolean. Path '', line 1, position 5." ); } diff --git a/Src/Newtonsoft.Json/Converters/UnixDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/UnixDateTimeConverter.cs index 8d1bc8b3..3e3feb6e 100644 --- a/Src/Newtonsoft.Json/Converters/UnixDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/UnixDateTimeConverter.cs @@ -34,10 +34,7 @@ namespace Newtonsoft.Json.Converters /// public class UnixDateTimeConverter : DateTimeConverterBase { - /// - /// Unix epoch time. Thursday, January 1, 1970 12:00:00 AM GMT - /// - public readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); /// /// Writes the JSON representation of the object. @@ -47,7 +44,7 @@ namespace Newtonsoft.Json.Converters /// The calling serializer. public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - long ticks = default; + long ticks; if (value is DateTime dateTime) { @@ -59,10 +56,14 @@ namespace Newtonsoft.Json.Converters ticks = (long)(dateTimeOffset.ToUniversalTime() - UnixEpoch).TotalSeconds; } #endif + else + { + throw new JsonSerializationException("Expected date object value."); + } if (ticks < 0) { - throw new JsonSerializationException("Expected a valid Unix date."); + throw new JsonSerializationException("Cannot convert date value that is before Unix epoch of 00:00:00 UTC on 1 January 1970."); } writer.WriteValue(ticks); @@ -78,43 +79,54 @@ namespace Newtonsoft.Json.Converters /// The object value. public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { + bool nullable = ReflectionUtils.IsNullable(objectType); if (reader.TokenType == JsonToken.Null) { - if (ReflectionUtils.IsNullable(objectType)) - return null; - else - throw JsonSerializationException.Create( - reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType) - ); + if (!nullable) + { + throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType)); + } + + return null; } - if (long.TryParse(reader.Value + "", out long ticks)) - { - if (ticks >= 0) - { - DateTime d = UnixEpoch.AddSeconds(ticks); + long ticks; -#if HAVE_DATE_TIME_OFFSET - Type t = (ReflectionUtils.IsNullableType(objectType)) - ? Nullable.GetUnderlyingType(objectType) - : objectType; - if (t == typeof(DateTimeOffset)) - { - return new DateTimeOffset(d, TimeSpan.Zero); - } -#endif - return d; + if (reader.TokenType == JsonToken.Integer) + { + ticks = (long)reader.Value; + } + else if (reader.TokenType == JsonToken.String) + { + if (!long.TryParse((string)reader.Value, out ticks)) + { + throw JsonSerializationException.Create(reader, "Cannot convert invalid value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType)); } - else - throw JsonSerializationException.Create( - reader, "Cannot convert invalid value {0} to {1}." - .FormatWith(CultureInfo.InvariantCulture, ticks, objectType) - ); } else - throw JsonSerializationException.Create( - reader, "Cannot convert invalid value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType) - ); + { + throw JsonSerializationException.Create(reader, "Unexpected token parsing date. Expected Integer or String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); + } + + if (ticks >= 0) + { + DateTime d = UnixEpoch.AddSeconds(ticks); + +#if HAVE_DATE_TIME_OFFSET + Type t = (nullable) + ? Nullable.GetUnderlyingType(objectType) + : objectType; + if (t == typeof(DateTimeOffset)) + { + return new DateTimeOffset(d, TimeSpan.Zero); + } +#endif + return d; + } + else + { + throw JsonSerializationException.Create(reader, "Cannot convert value that is before Unix epoch of 00:00:00 UTC on 1 January 1970 to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType)); + } } } } \ No newline at end of file