diff --git a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs index af4cf626..e5255075 100644 --- a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs @@ -225,17 +225,17 @@ now brown cow?", '"', true); value = (ulong)1; Assert.AreEqual("1", JsonConvert.ToString(value)); - value = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc); + value = new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc); Assert.AreEqual(@"""1970-01-01T00:00:00Z""", JsonConvert.ToString(value)); - value = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc); + value = new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc); Assert.AreEqual(@"""\/Date(0)\/""", JsonConvert.ToString((DateTime)value, DateFormatHandling.MicrosoftDateFormat, DateTimeZoneHandling.RoundtripKind)); #if !NET20 - value = new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, TimeSpan.Zero); + value = new DateTimeOffset(DateTimeUtils.InitialJavaScriptDateTicks, TimeSpan.Zero); Assert.AreEqual(@"""1970-01-01T00:00:00+00:00""", JsonConvert.ToString(value)); - value = new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, TimeSpan.Zero); + value = new DateTimeOffset(DateTimeUtils.InitialJavaScriptDateTicks, TimeSpan.Zero); Assert.AreEqual(@"""\/Date(0+0000)\/""", JsonConvert.ToString((DateTimeOffset)value, DateFormatHandling.MicrosoftDateFormat)); #endif @@ -366,10 +366,10 @@ now brown cow?", '"', true); Assert.AreEqual("2000-01-01T01:01:01" + GetOffset(year2000local, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); Assert.AreEqual("2000-01-01T01:01:01", result.IsoDateUnspecified); Assert.AreEqual(localToUtcDate, result.IsoDateUtc); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(year2000local) + GetOffset(year2000local, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(year2000local) + GetOffset(year2000local, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(year2000local) + GetOffset(year2000local, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(year2000local) + @")\/", result.MsDateUtc); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000local) + GetOffset(year2000local, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000local) + GetOffset(year2000local, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000local) + GetOffset(year2000local, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000local) + @")\/", result.MsDateUtc); DateTime millisecondsLocal = new DateTime(2000, 1, 1, 1, 1, 1, 999, DateTimeKind.Local); localToUtcDate = millisecondsLocal.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK"); @@ -379,10 +379,10 @@ now brown cow?", '"', true); Assert.AreEqual("2000-01-01T01:01:01.999" + GetOffset(millisecondsLocal, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); Assert.AreEqual("2000-01-01T01:01:01.999", result.IsoDateUnspecified); Assert.AreEqual(localToUtcDate, result.IsoDateUtc); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + GetOffset(millisecondsLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + GetOffset(millisecondsLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + GetOffset(millisecondsLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + @")\/", result.MsDateUtc); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + GetOffset(millisecondsLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + GetOffset(millisecondsLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + GetOffset(millisecondsLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + @")\/", result.MsDateUtc); DateTime ticksLocal = new DateTime(634663873826822481, DateTimeKind.Local); localToUtcDate = ticksLocal.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK"); @@ -392,10 +392,10 @@ now brown cow?", '"', true); Assert.AreEqual("2012-03-03T16:03:02.6822481" + GetOffset(ticksLocal, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); Assert.AreEqual("2012-03-03T16:03:02.6822481", result.IsoDateUnspecified); Assert.AreEqual(localToUtcDate, result.IsoDateUtc); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(ticksLocal) + GetOffset(ticksLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(ticksLocal) + GetOffset(ticksLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(ticksLocal) + GetOffset(ticksLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(ticksLocal) + @")\/", result.MsDateUtc); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(ticksLocal) + GetOffset(ticksLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(ticksLocal) + GetOffset(ticksLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(ticksLocal) + GetOffset(ticksLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(ticksLocal) + @")\/", result.MsDateUtc); DateTime year2000Unspecified = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Unspecified); @@ -404,10 +404,10 @@ now brown cow?", '"', true); Assert.AreEqual("2000-01-01T01:01:01" + GetOffset(year2000Unspecified, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); Assert.AreEqual("2000-01-01T01:01:01", result.IsoDateUnspecified); Assert.AreEqual("2000-01-01T01:01:01Z", result.IsoDateUtc); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(year2000Unspecified) + GetOffset(year2000Unspecified, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(year2000Unspecified) + GetOffset(year2000Unspecified, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(year2000Unspecified) + GetOffset(year2000Unspecified, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(year2000Unspecified.ToLocalTime()) + @")\/", result.MsDateUtc); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000Unspecified) + GetOffset(year2000Unspecified, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000Unspecified) + GetOffset(year2000Unspecified, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000Unspecified) + GetOffset(year2000Unspecified, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000Unspecified.ToLocalTime()) + @")\/", result.MsDateUtc); DateTime year2000Utc = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc); string utcTolocalDate = year2000Utc.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ss"); @@ -419,7 +419,7 @@ now brown cow?", '"', true); Assert.AreEqual("2000-01-01T01:01:01Z", result.IsoDateUtc); Assert.AreEqual(@"\/Date(946688461000)\/", result.MsDateRoundtrip); Assert.AreEqual(@"\/Date(946688461000" + GetOffset(year2000Utc, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(DateTime.SpecifyKind(year2000Utc, DateTimeKind.Unspecified)) + GetOffset(year2000Utc, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(DateTime.SpecifyKind(year2000Utc, DateTimeKind.Unspecified)) + GetOffset(year2000Utc, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); Assert.AreEqual(@"\/Date(946688461000)\/", result.MsDateUtc); DateTime unixEpoc = new DateTime(621355968000000000, DateTimeKind.Utc); @@ -432,7 +432,7 @@ now brown cow?", '"', true); Assert.AreEqual("1970-01-01T00:00:00Z", result.IsoDateUtc); Assert.AreEqual(@"\/Date(0)\/", result.MsDateRoundtrip); Assert.AreEqual(@"\/Date(0" + GetOffset(unixEpoc, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); - Assert.AreEqual(@"\/Date(" + JsonConvert.ConvertDateTimeToJavaScriptTicks(DateTime.SpecifyKind(unixEpoc, DateTimeKind.Unspecified)) + GetOffset(unixEpoc, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); + Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(DateTime.SpecifyKind(unixEpoc, DateTimeKind.Unspecified)) + GetOffset(unixEpoc, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); Assert.AreEqual(@"\/Date(0)\/", result.MsDateUtc); result = TestDateTime("DateTime Min", DateTime.MinValue); diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs index 063be42f..64bf7f05 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs @@ -2647,10 +2647,10 @@ bye", reader.Value); Assert.IsTrue(reader.Read()); Assert.IsTrue(reader.Read()); - Assert.AreEqual(new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc), reader.Value); + Assert.AreEqual(new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc), reader.Value); Assert.AreEqual(typeof(DateTime), reader.ValueType); Assert.IsTrue(reader.Read()); - Assert.AreEqual(new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc), reader.Value); + Assert.AreEqual(new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc), reader.Value); Assert.AreEqual(typeof(DateTime), reader.ValueType); Assert.IsTrue(reader.Read()); @@ -2660,10 +2660,10 @@ bye", reader.Value); Assert.IsTrue(reader.Read()); Assert.IsTrue(reader.Read()); - Assert.AreEqual(new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, TimeSpan.Zero), reader.Value); + Assert.AreEqual(new DateTimeOffset(DateTimeUtils.InitialJavaScriptDateTicks, TimeSpan.Zero), reader.Value); Assert.AreEqual(typeof(DateTimeOffset), reader.ValueType); Assert.IsTrue(reader.Read()); - Assert.AreEqual(new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, TimeSpan.Zero), reader.Value); + Assert.AreEqual(new DateTimeOffset(DateTimeUtils.InitialJavaScriptDateTicks, TimeSpan.Zero), reader.Value); Assert.AreEqual(typeof(DateTimeOffset), reader.ValueType); Assert.IsTrue(reader.Read()); #endif @@ -2686,10 +2686,10 @@ bye", reader.Value); Assert.IsTrue(reader.Read()); reader.ReadAsDateTimeOffset(); - Assert.AreEqual(new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, TimeSpan.Zero), reader.Value); + Assert.AreEqual(new DateTimeOffset(DateTimeUtils.InitialJavaScriptDateTicks, TimeSpan.Zero), reader.Value); Assert.AreEqual(typeof(DateTimeOffset), reader.ValueType); reader.ReadAsDateTimeOffset(); - Assert.AreEqual(new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, TimeSpan.Zero), reader.Value); + Assert.AreEqual(new DateTimeOffset(DateTimeUtils.InitialJavaScriptDateTicks, TimeSpan.Zero), reader.Value); Assert.AreEqual(typeof(DateTimeOffset), reader.ValueType); Assert.IsTrue(reader.Read()); @@ -2699,10 +2699,10 @@ bye", reader.Value); Assert.IsTrue(reader.Read()); reader.ReadAsDateTime(); - Assert.AreEqual(new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc), reader.Value); + Assert.AreEqual(new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc), reader.Value); Assert.AreEqual(typeof(DateTime), reader.ValueType); reader.ReadAsDateTime(); - Assert.AreEqual(new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc), reader.Value); + Assert.AreEqual(new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc), reader.Value); Assert.AreEqual(typeof(DateTime), reader.ValueType); Assert.IsTrue(reader.Read()); #endif diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs index b0cf0f28..85be33ef 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs @@ -144,10 +144,10 @@ namespace Newtonsoft.Json.Tests jsonWriter.WriteValue((decimal?)null); jsonWriter.WriteValue((decimal?)1.1m); jsonWriter.WriteValue((DateTime?)null); - jsonWriter.WriteValue((DateTime?)new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc)); + jsonWriter.WriteValue((DateTime?)new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc)); #if !NET20 jsonWriter.WriteValue((DateTimeOffset?)null); - jsonWriter.WriteValue((DateTimeOffset?)new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, TimeSpan.Zero)); + jsonWriter.WriteValue((DateTimeOffset?)new DateTimeOffset(DateTimeUtils.InitialJavaScriptDateTicks, TimeSpan.Zero)); #endif jsonWriter.WriteEndArray(); } @@ -731,6 +731,46 @@ namespace Newtonsoft.Json.Tests Assert.AreEqual(@"[0.0,0.0,0.1,1.0,1.000001,1E-06,4.94065645841247E-324,Infinity,-Infinity,NaN,1.7976931348623157E+308,-1.7976931348623157E+308,Infinity,-Infinity,NaN]", sb.ToString()); } + [Test] + public void WriteIntegerNumber() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + using (JsonWriter jsonWriter = new JsonTextWriter(sw) { Formatting = Formatting.Indented }) + { + jsonWriter.WriteStartArray(); + + jsonWriter.WriteValue(0); + jsonWriter.WriteValue(-0); + jsonWriter.WriteValue(9L); + jsonWriter.WriteValue(9UL); + jsonWriter.WriteValue(int.MaxValue); + jsonWriter.WriteValue(int.MinValue); + jsonWriter.WriteValue(long.MaxValue); + jsonWriter.WriteValue(long.MinValue); + jsonWriter.WriteValue(ulong.MaxValue); + jsonWriter.WriteValue(ulong.MinValue); + + jsonWriter.WriteEndArray(); + } + + Console.WriteLine(sb.ToString()); + + Assert.AreEqual(@"[ + 0, + 0, + 9, + 9, + 2147483647, + -2147483648, + 9223372036854775807, + -9223372036854775808, + 18446744073709551615, + 0 +]", sb.ToString()); + } + [Test] public void BadWriteEndArray() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs index b93d0e76..5ac84a4a 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs @@ -50,6 +50,7 @@ using Newtonsoft.Json.Utilities.LinqBridge; #else using System.Linq; #endif +using Newtonsoft.Json.Utilities; namespace Newtonsoft.Json.Tests.Linq { @@ -419,7 +420,7 @@ Parameter name: arrayIndex", JArray a = (JArray)JsonConvert.DeserializeObject(json); JValue v = (JValue)a[0]; - Assert.AreEqual(JsonConvert.ConvertJavaScriptTicksToDateTime(1207285200000), (DateTime)v); + Assert.AreEqual(DateTimeUtils.ConvertJavaScriptTicksToDateTime(1207285200000), (DateTime)v); } [Test] diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs index 388650db..31010f22 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs @@ -43,6 +43,7 @@ using System.IO; using Newtonsoft.Json.Utilities.LinqBridge; #else using System.Linq; +using Newtonsoft.Json.Utilities; #endif namespace Newtonsoft.Json.Tests.Linq @@ -90,7 +91,7 @@ namespace Newtonsoft.Json.Tests.Linq DateParseHandling = DateParseHandling.DateTimeOffset }); Assert.AreEqual(typeof(DateTimeOffset), v.Value.GetType()); - Assert.AreEqual(new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, new TimeSpan(12, 31, 0)), v.Value); + Assert.AreEqual(new DateTimeOffset(DateTimeUtils.InitialJavaScriptDateTicks, new TimeSpan(12, 31, 0)), v.Value); #endif } diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj index 90d16248..4c6692d6 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj @@ -236,8 +236,10 @@ + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj index 0ff3fca1..a6a73c28 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj @@ -278,8 +278,10 @@ + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj index 8d00be08..0de0113d 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj @@ -396,6 +396,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj index 7066587a..c9156e94 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj @@ -277,6 +277,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj index fc0545ad..23145fd4 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj @@ -277,6 +277,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index 4f911eeb..4c508c25 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -340,6 +340,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs index 1e525635..2aa87889 100644 --- a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs +++ b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs @@ -64,8 +64,8 @@ namespace Newtonsoft.Json.Tests [TestFixture] public class PerformanceTests : TestFixtureBase { - //private const int Iterations = 100; - private const int Iterations = 5000; + private const int Iterations = 100; + //private const int Iterations = 5000; #region Data @@ -105,7 +105,7 @@ namespace Newtonsoft.Json.Tests [Test] public void SerializeSimpleObject() { - var value = CreateSimpleObject(); + SimpleObject value = CreateSimpleObject(); SerializeTests(value); } @@ -140,19 +140,19 @@ namespace Newtonsoft.Json.Tests [Test] public void Deserialize() { - //BenchmarkDeserializeMethod(SerializeMethod.DataContractSerializer, XmlText); - //BenchmarkDeserializeMethod(SerializeMethod.BinaryFormatter, MiscellaneousUtils.HexToBytes(BinaryFormatterHex)); + BenchmarkDeserializeMethod(SerializeMethod.DataContractSerializer, XmlText); + BenchmarkDeserializeMethod(SerializeMethod.BinaryFormatter, HexToBytes(BinaryFormatterHex)); DeserializeTests(JsonText); - //BenchmarkDeserializeMethod(SerializeMethod.JsonNetWithIsoConverter, JsonIsoText); - //BenchmarkDeserializeMethod(SerializeMethod.JsonNetBinary, MiscellaneousUtils.HexToBytes(BsonHex)); + BenchmarkDeserializeMethod(SerializeMethod.JsonNetWithIsoConverter, JsonIsoText); + BenchmarkDeserializeMethod(SerializeMethod.JsonNetBinary, HexToBytes(BsonHex)); } public void DeserializeTests(string json) { - //BenchmarkDeserializeMethod(SerializeMethod.JavaScriptSerializer, json); - //BenchmarkDeserializeMethod(SerializeMethod.DataContractJsonSerializer, json); + BenchmarkDeserializeMethod(SerializeMethod.JavaScriptSerializer, json); + BenchmarkDeserializeMethod(SerializeMethod.DataContractJsonSerializer, json); BenchmarkDeserializeMethod(SerializeMethod.JsonNet, json); - //BenchmarkDeserializeMethod(SerializeMethod.JsonNetManual, json); + BenchmarkDeserializeMethod(SerializeMethod.JsonNetManual, json); } [Test] diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs index 6fd50297..ee097193 100644 --- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs @@ -75,4 +75,4 @@ using System.Security; // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] -[assembly: AssemblyFileVersion("5.0.1.16008")] +[assembly: AssemblyFileVersion("5.0.4.16021")] diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 517a8aae..416e832a 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -1231,7 +1231,7 @@ keyword such as type of business."" [Test] public void SerializerShouldUseMemberConverter_IsoDate() { - DateTime testDate = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc); + DateTime testDate = new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc); MemberConverterClass m1 = new MemberConverterClass { DefaultConverter = testDate, MemberConverter = testDate }; string json = JsonConvert.SerializeObject(m1); @@ -1246,7 +1246,7 @@ keyword such as type of business."" [Test] public void SerializerShouldUseMemberConverter_MsDate() { - DateTime testDate = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc); + DateTime testDate = new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc); MemberConverterClass m1 = new MemberConverterClass { DefaultConverter = testDate, MemberConverter = testDate }; string json = JsonConvert.SerializeObject(m1, new JsonSerializerSettings @@ -1264,7 +1264,7 @@ keyword such as type of business."" [Test] public void SerializerShouldUseMemberConverter_MsDate_DateParseNone() { - DateTime testDate = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc); + DateTime testDate = new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc); MemberConverterClass m1 = new MemberConverterClass { DefaultConverter = testDate, MemberConverter = testDate }; string json = JsonConvert.SerializeObject(m1, new JsonSerializerSettings @@ -1287,7 +1287,7 @@ keyword such as type of business."" [Test] public void SerializerShouldUseMemberConverter_IsoDate_DateParseNone() { - DateTime testDate = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc); + DateTime testDate = new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc); MemberConverterClass m1 = new MemberConverterClass { DefaultConverter = testDate, MemberConverter = testDate }; string json = JsonConvert.SerializeObject(m1, new JsonSerializerSettings @@ -1305,7 +1305,7 @@ keyword such as type of business."" [Test] public void SerializerShouldUseMemberConverterOverArgumentConverter() { - DateTime testDate = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc); + DateTime testDate = new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc); MemberConverterClass m1 = new MemberConverterClass { DefaultConverter = testDate, MemberConverter = testDate }; string json = JsonConvert.SerializeObject(m1, new JavaScriptDateTimeConverter()); @@ -6807,9 +6807,9 @@ Parameter name: value", Venue = "Gryphon Theatre", Performances = new List { - JsonConvert.ConvertJavaScriptTicksToDateTime(1336458600000), - JsonConvert.ConvertJavaScriptTicksToDateTime(1336545000000), - JsonConvert.ConvertJavaScriptTicksToDateTime(1336636800000) + DateTimeUtils.ConvertJavaScriptTicksToDateTime(1336458600000), + DateTimeUtils.ConvertJavaScriptTicksToDateTime(1336545000000), + DateTimeUtils.ConvertJavaScriptTicksToDateTime(1336636800000) } }; diff --git a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs index edcc751a..802853cf 100644 --- a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs +++ b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs @@ -69,11 +69,10 @@ namespace Newtonsoft.Json.Tests protected string GetOffset(DateTime d, DateFormatHandling dateFormatHandling) { - StringWriter sw = new StringWriter(); - JsonConvert.WriteDateTimeOffset(sw, DateTime.SpecifyKind(d, DateTimeKind.Local).GetUtcOffset(), dateFormatHandling); - sw.Flush(); + char[] chars = new char[8]; + int pos = DateTimeUtils.WriteDateTimeOffset(chars, 0, DateTime.SpecifyKind(d, DateTimeKind.Local).GetUtcOffset(), dateFormatHandling); - return sw.ToString(); + return new string(chars, 0, pos); } protected string BytesToHex(byte[] bytes) diff --git a/Src/Newtonsoft.Json.Tests/Utilities/DateTimeUtilsTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/DateTimeUtilsTests.cs new file mode 100644 index 00000000..689d8f73 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Utilities/DateTimeUtilsTests.cs @@ -0,0 +1,193 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Tests.Utilities +{ + [TestFixture] + public class DateTimeUtilsTests : TestFixtureBase + { + [Test] + public void NewDateTimeParse() + { + AssertNewDateTimeParseEqual("999x-12-31T23:59:59"); + AssertNewDateTimeParseEqual("9999x12-31T23:59:59"); + AssertNewDateTimeParseEqual("9999-1x-31T23:59:59"); + AssertNewDateTimeParseEqual("9999-12x31T23:59:59"); + AssertNewDateTimeParseEqual("9999-12-3xT23:59:59"); + AssertNewDateTimeParseEqual("9999-12-31x23:59:59"); + AssertNewDateTimeParseEqual("9999-12-31T2x:59:59"); + AssertNewDateTimeParseEqual("9999-12-31T23x59:59"); + AssertNewDateTimeParseEqual("9999-12-31T23:5x:59"); + AssertNewDateTimeParseEqual("9999-12-31T23:59x59"); + AssertNewDateTimeParseEqual("9999-12-31T23:59:5x"); + AssertNewDateTimeParseEqual("9999-12-31T23:59:5"); + AssertNewDateTimeParseEqual("9999-12-31T23:59:59.x"); + AssertNewDateTimeParseEqual("9999-12-31T23:59:59.99999999"); + AssertNewDateTimeParseEqual("9999-12-31T23:59:59.", null); // DateTime.TryParse is bugged and should return null + + AssertNewDateTimeParseEqual("2000-12-15T22:11:03.055Z"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03.055"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03.055+00:00"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03.055+23:30"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03.055-23:30"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03.055+11:30"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03.055-11:30"); + + AssertNewDateTimeParseEqual("2000-12-15T22:11:03Z"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03+00:00"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03+23:30"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03-23:30"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03+11:30"); + AssertNewDateTimeParseEqual("2000-12-15T22:11:03-11:30"); + + AssertNewDateTimeParseEqual("0001-01-01T00:00:00Z"); + AssertNewDateTimeParseEqual("0001-01-01T00:00:00"); + AssertNewDateTimeParseEqual("0001-01-01T00:00:00+00:00"); + //AssertNewDateTimeParseEqual("0001-01-01T00:00:00+23:30"); // I don't know why a different value is returned from DateTime.TryParse, I think it is a bug in .NET + AssertNewDateTimeParseEqual("0001-01-01T00:00:00-23:30"); + AssertNewDateTimeParseEqual("0001-01-01T00:00:00+11:30"); + AssertNewDateTimeParseEqual("0001-01-01T00:00:00-11:30"); + + AssertNewDateTimeParseEqual("9999-12-31T23:59:59.9999999Z"); + AssertNewDateTimeParseEqual("9999-12-31T23:59:59.9999999"); + AssertNewDateTimeParseEqual("9999-12-31T23:59:59.9999999+00:00", DateTime.MaxValue); // DateTime.TryParse fails instead of returning MaxDate + AssertNewDateTimeParseEqual("9999-12-31T23:59:59.9999999+23:30"); + AssertNewDateTimeParseEqual("9999-12-31T23:59:59.9999999-23:30", DateTime.MaxValue); // DateTime.TryParse fails instead of returning MaxDate + AssertNewDateTimeParseEqual("9999-12-31T23:59:59.9999999+11:30", DateTime.MaxValue); // DateTime.TryParse fails instead of returning MaxDate + AssertNewDateTimeParseEqual("9999-12-31T23:59:59.9999999-11:30", DateTime.MaxValue); // DateTime.TryParse fails instead of returning MaxDate + } + + private void AssertNewDateTimeParseEqual(string text, object oldDate) + { + object newDt; + DateTimeUtils.TryParseDateIso(text, DateParseHandling.DateTime, DateTimeZoneHandling.RoundtripKind, out newDt); + + if (!Equals(oldDate, newDt)) + { + Assert.AreEqual(oldDate, newDt, "DateTime parse not equal. Text: '{0}' Old ticks: {1} New ticks: {2}".FormatWith( + CultureInfo.InvariantCulture, + text, + oldDate != null ? ((DateTime)oldDate).Ticks : (long?)null, + newDt != null ? ((DateTime)newDt).Ticks : (long?)null + )); + } + } + + private void AssertNewDateTimeParseEqual(string text) + { + object oldDt; + TryParseDateIso(text, DateParseHandling.DateTime, DateTimeZoneHandling.RoundtripKind, out oldDt); + + AssertNewDateTimeParseEqual(text, oldDt); + } + +#if !NET20 + [Test] + public void NewDateTimeOffsetParse() + { + AssertNewDateTimeOffsetParseEqual("0001-01-01T00:00:00"); + + AssertNewDateTimeOffsetParseEqual("2000-12-15T22:11:03.055Z"); + AssertNewDateTimeOffsetParseEqual("2000-12-15T22:11:03.055"); + AssertNewDateTimeOffsetParseEqual("2000-12-15T22:11:03.055+00:00"); + AssertNewDateTimeOffsetParseEqual("2000-12-15T22:11:03.055+13:30"); + AssertNewDateTimeOffsetParseEqual("2000-12-15T22:11:03.055-13:30"); + + AssertNewDateTimeOffsetParseEqual("2000-12-15T22:11:03Z"); + AssertNewDateTimeOffsetParseEqual("2000-12-15T22:11:03"); + AssertNewDateTimeOffsetParseEqual("2000-12-15T22:11:03+00:00"); + AssertNewDateTimeOffsetParseEqual("2000-12-15T22:11:03+13:30"); + AssertNewDateTimeOffsetParseEqual("2000-12-15T22:11:03-13:30"); + + AssertNewDateTimeOffsetParseEqual("0001-01-01T00:00:00Z"); + AssertNewDateTimeOffsetParseEqual("0001-01-01T00:00:00+00:00"); + AssertNewDateTimeOffsetParseEqual("0001-01-01T00:00:00+13:30"); + AssertNewDateTimeOffsetParseEqual("0001-01-01T00:00:00-13:30"); + + AssertNewDateTimeOffsetParseEqual("9999-12-31T23:59:59.9999999Z"); + AssertNewDateTimeOffsetParseEqual("9999-12-31T23:59:59.9999999"); + AssertNewDateTimeOffsetParseEqual("9999-12-31T23:59:59.9999999+00:00"); + AssertNewDateTimeOffsetParseEqual("9999-12-31T23:59:59.9999999+13:30"); + AssertNewDateTimeOffsetParseEqual("9999-12-31T23:59:59.9999999-13:30"); + } + + private void AssertNewDateTimeOffsetParseEqual(string text) + { + object oldDt; + object newDt; + TryParseDateIso(text, DateParseHandling.DateTimeOffset, DateTimeZoneHandling.Unspecified, out oldDt); + DateTimeUtils.TryParseDateIso(text, DateParseHandling.DateTimeOffset, DateTimeZoneHandling.Unspecified, out newDt); + + if (!Equals(oldDt, newDt)) + { + Assert.AreEqual(oldDt, newDt, "DateTimeOffset parse not equal. Text: '{0}' Old ticks: {1} New ticks: {2}".FormatWith( + CultureInfo.InvariantCulture, + text, + ((DateTime)oldDt).Ticks, + ((DateTime)newDt).Ticks)); + } + } +#endif + + internal static bool TryParseDateIso(string text, DateParseHandling dateParseHandling, DateTimeZoneHandling dateTimeZoneHandling, out object dt) + { + const string isoDateFormat = "yyyy-MM-ddTHH:mm:ss.FFFFFFFK"; + +#if !NET20 + if (dateParseHandling == DateParseHandling.DateTimeOffset) + { + DateTimeOffset dateTimeOffset; + if (DateTimeOffset.TryParseExact(text, isoDateFormat, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateTimeOffset)) + { + dt = dateTimeOffset; + return true; + } + } + else +#endif + { + DateTime dateTime; + if (DateTime.TryParseExact(text, isoDateFormat, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateTime)) + { + dateTime = DateTimeUtils.EnsureDateTime(dateTime, dateTimeZoneHandling); + + dt = dateTime; + return true; + } + } + + dt = null; + return false; + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs index 0a36100f..24d32a28 100644 --- a/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs +++ b/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs @@ -25,6 +25,7 @@ #if !(SILVERLIGHT || PORTABLE || NETFX_CORE || PORTABLE40) using System; +using System.Diagnostics; using System.Reflection; #if !NETFX_CORE using NUnit.Framework; @@ -74,6 +75,8 @@ namespace Newtonsoft.Json.Tests.Utilities Assert.AreEqual(m.Name, "Hi"); setter(p, "Hi"); + + Assert.AreEqual(p.Name, "Hi"); }); } @@ -124,42 +127,6 @@ namespace Newtonsoft.Json.Tests.Utilities JsonSerializerTest.DictionaryKey key = (JsonSerializerTest.DictionaryKey) result; Assert.AreEqual("First!", key.Value); } - - //[Test] - //public void sdfsdf() - //{ - // string name = "MyAssembly"; - // string filename = name + ".dll"; - - // AssemblyName s = new AssemblyName(name); - - // AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(s, AssemblyBuilderAccess.RunAndSave); - // ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(filename, filename); - // TypeBuilder typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Class, typeof(object)); - // MethodBuilder methodBuilder = typeBuilder.DefineMethod("TestSet", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { typeof(object), typeof(object) }); - - // DynamicReflectionDelegateFactory.GenerateCreateSetFieldIL(typeof(ClassWithGuid).GetField("GuidField"), methodBuilder.GetILGenerator()); - // typeBuilder.CreateType(); - // assemblyBuilder.Save(filename); - //} - - //[Test] - //public void sdfsdf1() - //{ - // string name = "MyAssembly1"; - // string filename = name + ".dll"; - - // AssemblyName s = new AssemblyName(name); - - // AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(s, AssemblyBuilderAccess.RunAndSave); - // ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(filename, filename); - // TypeBuilder typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Class, typeof(object)); - // MethodBuilder methodBuilder = typeBuilder.DefineMethod("TestSet", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { typeof(object), typeof(object) }); - - // DynamicReflectionDelegateFactory.GenerateCreateSetPropertyIL(typeof(Car).GetProperty("Model"), methodBuilder.GetILGenerator()); - // typeBuilder.CreateType(); - // assemblyBuilder.Save(filename); - //} } } #endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs index 6ff45554..387cac9c 100644 --- a/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs +++ b/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs @@ -1,7 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + using NUnit.Framework; using Newtonsoft.Json.Utilities; diff --git a/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs b/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs index 65908a3e..33d19e7c 100644 --- a/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs +++ b/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs @@ -146,13 +146,13 @@ namespace Newtonsoft.Json.Bson else if (DateTimeKindHandling == DateTimeKind.Local) dateTime = dateTime.ToLocalTime(); - ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(dateTime, false); + ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(dateTime, false); } #if !NET20 else { DateTimeOffset dateTimeOffset = (DateTimeOffset)value.Value; - ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(dateTimeOffset.UtcDateTime, dateTimeOffset.Offset); + ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(dateTimeOffset.UtcDateTime, dateTimeOffset.Offset); } #endif diff --git a/Src/Newtonsoft.Json/Bson/BsonReader.cs b/Src/Newtonsoft.Json/Bson/BsonReader.cs index 8d1e6e27..813b5de0 100644 --- a/Src/Newtonsoft.Json/Bson/BsonReader.cs +++ b/Src/Newtonsoft.Json/Bson/BsonReader.cs @@ -550,7 +550,7 @@ namespace Newtonsoft.Json.Bson break; case BsonType.Date: long ticks = ReadInt64(); - DateTime utcDateTime = JsonConvert.ConvertJavaScriptTicksToDateTime(ticks); + DateTime utcDateTime = DateTimeUtils.ConvertJavaScriptTicksToDateTime(ticks); DateTime dateTime; switch (DateTimeKindHandling) diff --git a/Src/Newtonsoft.Json/Bson/BsonWriter.cs b/Src/Newtonsoft.Json/Bson/BsonWriter.cs index 3ebef070..20d8374c 100644 --- a/Src/Newtonsoft.Json/Bson/BsonWriter.cs +++ b/Src/Newtonsoft.Json/Bson/BsonWriter.cs @@ -425,7 +425,7 @@ namespace Newtonsoft.Json.Bson public override void WriteValue(DateTime value) { base.WriteValue(value); - value = JsonConvert.EnsureDateTime(value, DateTimeZoneHandling); + value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling); AddValue(value, BsonType.Date); } diff --git a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs index af20d53a..31fa7102 100644 --- a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs @@ -48,14 +48,14 @@ namespace Newtonsoft.Json.Converters { DateTime dateTime = (DateTime)value; DateTime utcDateTime = dateTime.ToUniversalTime(); - ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(utcDateTime); + ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(utcDateTime); } #if !NET20 else if (value is DateTimeOffset) { DateTimeOffset dateTimeOffset = (DateTimeOffset)value; DateTimeOffset utcDateTimeOffset = dateTimeOffset.ToUniversalTime(); - ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(utcDateTimeOffset.UtcDateTime); + ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(utcDateTimeOffset.UtcDateTime); } #endif else @@ -100,7 +100,7 @@ namespace Newtonsoft.Json.Converters long ticks = (long)reader.Value; - DateTime d = JsonConvert.ConvertJavaScriptTicksToDateTime(ticks); + DateTime d = DateTimeUtils.ConvertJavaScriptTicksToDateTime(ticks); reader.Read(); diff --git a/Src/Newtonsoft.Json/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs index a64572bc..c86240d4 100644 --- a/Src/Newtonsoft.Json/JsonConvert.cs +++ b/Src/Newtonsoft.Json/JsonConvert.cs @@ -86,8 +86,6 @@ namespace Newtonsoft.Json /// public static readonly string NaN = "NaN"; - internal static readonly long InitialJavaScriptDateTicks = 621355968000000000; - /// /// Converts the to its JSON string representation. /// @@ -107,39 +105,17 @@ namespace Newtonsoft.Json /// A JSON string representation of the . public static string ToString(DateTime value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling) { - DateTime updatedDateTime = EnsureDateTime(value, timeZoneHandling); + DateTime updatedDateTime = DateTimeUtils.EnsureDateTime(value, timeZoneHandling); using (StringWriter writer = StringUtils.CreateStringWriter(64)) { writer.Write('"'); - WriteDateTimeString(writer, updatedDateTime, updatedDateTime.GetUtcOffset(), updatedDateTime.Kind, format); + DateTimeUtils.WriteDateTimeString(writer, updatedDateTime, format, null, CultureInfo.InvariantCulture); writer.Write('"'); return writer.ToString(); } } - internal static DateTime EnsureDateTime(DateTime value, DateTimeZoneHandling timeZone) - { - switch (timeZone) - { - case DateTimeZoneHandling.Local: - value = SwitchToLocalTime(value); - break; - case DateTimeZoneHandling.Utc: - value = SwitchToUtcTime(value); - break; - case DateTimeZoneHandling.Unspecified: - value = new DateTime(value.Ticks, DateTimeKind.Unspecified); - break; - case DateTimeZoneHandling.RoundtripKind: - break; - default: - throw new ArgumentException("Invalid date time handling value."); - } - - return value; - } - #if !NET20 /// /// Converts the to its JSON string representation. @@ -162,231 +138,13 @@ namespace Newtonsoft.Json using (StringWriter writer = StringUtils.CreateStringWriter(64)) { writer.Write('"'); - WriteDateTimeOffsetString(writer, value, format, null, CultureInfo.InvariantCulture); + DateTimeUtils.WriteDateTimeOffsetString(writer, value, format, null, CultureInfo.InvariantCulture); writer.Write('"'); return writer.ToString(); } } - - internal static void WriteDateTimeOffsetString(TextWriter writer, DateTimeOffset value, DateFormatHandling format, string formatString, CultureInfo culture) - { - if (string.IsNullOrEmpty(formatString)) - { - WriteDateTimeString(writer, (format == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, format); - } - else - { - writer.Write(value.ToString(formatString, culture)); - } - } #endif - internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format, string formatString, CultureInfo culture) - { - if (string.IsNullOrEmpty(formatString)) - { - WriteDateTimeString(writer, value, value.GetUtcOffset(), value.Kind, format); - } - else - { - writer.Write(value.ToString(formatString, culture)); - } - } - - internal static void WriteDateTimeString(TextWriter writer, DateTime value, TimeSpan offset, DateTimeKind kind, DateFormatHandling format) - { - if (format == DateFormatHandling.MicrosoftDateFormat) - { - long javaScriptTicks = ConvertDateTimeToJavaScriptTicks(value, offset); - - writer.Write(@"\/Date("); - writer.Write(javaScriptTicks); - - switch (kind) - { - case DateTimeKind.Unspecified: - if (value != DateTime.MaxValue && value != DateTime.MinValue) - WriteDateTimeOffset(writer, offset, format); - break; - case DateTimeKind.Local: - WriteDateTimeOffset(writer, offset, format); - break; - } - - writer.Write(@")\/"); - } - else - { - WriteIsoDate(writer, value); - - switch (kind) - { - case DateTimeKind.Local: - WriteDateTimeOffset(writer, offset, format); - break; - case DateTimeKind.Utc: - writer.Write("Z"); - break; - } - - } - } - - internal static void WriteIsoDate(TextWriter writer, DateTime dt) - { - char[] chars = new char[27]; - int length = 19; - - IntToCharArray(chars, 0, dt.Year, 4); - chars[4] = '-'; - IntToCharArray(chars, 5, dt.Month, 2); - chars[7] = '-'; - IntToCharArray(chars, 8, dt.Day, 2); - chars[10] = 'T'; - IntToCharArray(chars, 11, dt.Hour, 2); - chars[13] = ':'; - IntToCharArray(chars, 14, dt.Minute, 2); - chars[16] = ':'; - IntToCharArray(chars, 17, dt.Second, 2); - - DateTime time = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second); - int fraction = (int)(dt.Ticks - time.Ticks); - - if (fraction != 0) - { - int digits = 7; - while ((fraction % 10) == 0) - { - digits--; - fraction /= 10; - } - - chars[19] = '.'; - IntToCharArray(chars, 20, fraction, digits); - - length += digits + 1; - } - - writer.Write(chars, 0, length); - } - - private static void IntToCharArray(char[] text, int start, int value, int digits) - { - while (digits-- != 0) - { - text[start + digits] = (char)((value % 10) + 48); - value /= 10; - } - } - - internal static void WriteDateTimeOffset(TextWriter writer, TimeSpan offset, DateFormatHandling format) - { - writer.Write((offset.Ticks >= 0L) ? "+" : "-"); - - int absHours = Math.Abs(offset.Hours); - if (absHours < 10) - writer.Write(0); - writer.Write(absHours); - - if (format == DateFormatHandling.IsoDateFormat) - writer.Write(':'); - - int absMinutes = Math.Abs(offset.Minutes); - if (absMinutes < 10) - writer.Write(0); - writer.Write(absMinutes); - } - - private static long ToUniversalTicks(DateTime dateTime) - { - if (dateTime.Kind == DateTimeKind.Utc) - return dateTime.Ticks; - - return ToUniversalTicks(dateTime, dateTime.GetUtcOffset()); - } - - private static long ToUniversalTicks(DateTime dateTime, TimeSpan offset) - { - // special case min and max value - // they never have a timezone appended to avoid issues - if (dateTime.Kind == DateTimeKind.Utc || dateTime == DateTime.MaxValue || dateTime == DateTime.MinValue) - return dateTime.Ticks; - - long ticks = dateTime.Ticks - offset.Ticks; - if (ticks > 3155378975999999999L) - return 3155378975999999999L; - - if (ticks < 0L) - return 0L; - - return ticks; - } - - internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, TimeSpan offset) - { - long universialTicks = ToUniversalTicks(dateTime, offset); - - return UniversialTicksToJavaScriptTicks(universialTicks); - } - - internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime) - { - return ConvertDateTimeToJavaScriptTicks(dateTime, true); - } - - internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, bool convertToUtc) - { - long ticks = (convertToUtc) ? ToUniversalTicks(dateTime) : dateTime.Ticks; - - return UniversialTicksToJavaScriptTicks(ticks); - } - - private static long UniversialTicksToJavaScriptTicks(long universialTicks) - { - long javaScriptTicks = (universialTicks - InitialJavaScriptDateTicks)/10000; - - return javaScriptTicks; - } - - internal static DateTime ConvertJavaScriptTicksToDateTime(long javaScriptTicks) - { - DateTime dateTime = new DateTime((javaScriptTicks*10000) + InitialJavaScriptDateTicks, DateTimeKind.Utc); - - return dateTime; - } - - private static DateTime SwitchToLocalTime(DateTime value) - { - switch (value.Kind) - { - case DateTimeKind.Unspecified: - return new DateTime(value.Ticks, DateTimeKind.Local); - - case DateTimeKind.Utc: - return value.ToLocalTime(); - - case DateTimeKind.Local: - return value; - } - return value; - } - - private static DateTime SwitchToUtcTime(DateTime value) - { - switch (value.Kind) - { - case DateTimeKind.Unspecified: - return new DateTime(value.Ticks, DateTimeKind.Utc); - - case DateTimeKind.Utc: - return value; - - case DateTimeKind.Local: - return value.ToUniversalTime(); - } - return value; - } - /// /// Converts the to its JSON string representation. /// @@ -740,126 +498,6 @@ namespace Newtonsoft.Json return false; } - internal static bool TryParseDateTime(string s, DateParseHandling dateParseHandling, DateTimeZoneHandling dateTimeZoneHandling, out object dt) - { - if (s.Length > 0) - { - if (s[0] == '/') - { - if (s.StartsWith("/Date(", StringComparison.Ordinal) && s.EndsWith(")/", StringComparison.Ordinal)) - { - return TryParseDateMicrosoft(s, dateParseHandling, dateTimeZoneHandling, out dt); - } - } - else if (char.IsDigit(s[0]) && s.Length >= 19 && s.Length <= 40) - { - return TryParseDateIso(s, dateParseHandling, dateTimeZoneHandling, out dt); - } - } - - dt = null; - return false; - } - - private static bool TryParseDateIso(string text, DateParseHandling dateParseHandling, DateTimeZoneHandling dateTimeZoneHandling, out object dt) - { - const string isoDateFormat = "yyyy-MM-ddTHH:mm:ss.FFFFFFFK"; - -#if !NET20 - if (dateParseHandling == DateParseHandling.DateTimeOffset) - { - DateTimeOffset dateTimeOffset; - if (DateTimeOffset.TryParseExact(text, isoDateFormat, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateTimeOffset)) - { - dt = dateTimeOffset; - return true; - } - } - else -#endif - { - DateTime dateTime; - if (DateTime.TryParseExact(text, isoDateFormat, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateTime)) - { - dateTime = EnsureDateTime(dateTime, dateTimeZoneHandling); - - dt = dateTime; - return true; - } - } - - dt = null; - return false; - } - - private static bool TryParseDateMicrosoft(string text, DateParseHandling dateParseHandling, DateTimeZoneHandling dateTimeZoneHandling, out object dt) - { - string value = text.Substring(6, text.Length - 8); - DateTimeKind kind = DateTimeKind.Utc; - - int index = value.IndexOf('+', 1); - - if (index == -1) - index = value.IndexOf('-', 1); - - TimeSpan offset = TimeSpan.Zero; - - if (index != -1) - { - kind = DateTimeKind.Local; - offset = ReadOffset(value.Substring(index)); - value = value.Substring(0, index); - } - - long javaScriptTicks = long.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); - - DateTime utcDateTime = ConvertJavaScriptTicksToDateTime(javaScriptTicks); - -#if !NET20 - if (dateParseHandling == DateParseHandling.DateTimeOffset) - { - dt = new DateTimeOffset(utcDateTime.Add(offset).Ticks, offset); - return true; - } - else -#endif - { - DateTime dateTime; - - switch (kind) - { - case DateTimeKind.Unspecified: - dateTime = DateTime.SpecifyKind(utcDateTime.ToLocalTime(), DateTimeKind.Unspecified); - break; - case DateTimeKind.Local: - dateTime = utcDateTime.ToLocalTime(); - break; - default: - dateTime = utcDateTime; - break; - } - - dt = EnsureDateTime(dateTime, dateTimeZoneHandling); - return true; - } - } - - private static TimeSpan ReadOffset(string offsetText) - { - bool negative = (offsetText[0] == '-'); - - int hours = int.Parse(offsetText.Substring(1, 2), NumberStyles.Integer, CultureInfo.InvariantCulture); - int minutes = 0; - if (offsetText.Length >= 5) - minutes = int.Parse(offsetText.Substring(3, 2), NumberStyles.Integer, CultureInfo.InvariantCulture); - - TimeSpan offset = TimeSpan.FromHours(hours) + TimeSpan.FromMinutes(minutes); - if (negative) - offset = offset.Negate(); - - return offset; - } - #region Serialize /// /// Serializes the specified object to a JSON string. diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index 2960b736..c7990325 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -700,7 +700,7 @@ namespace Newtonsoft.Json if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt)) { - dt = JsonConvert.EnsureDateTime(dt, DateTimeZoneHandling); + dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling); SetToken(JsonToken.Date, dt); return dt; } diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs index 79bc7280..ca65b01d 100644 --- a/Src/Newtonsoft.Json/JsonSerializer.cs +++ b/Src/Newtonsoft.Json/JsonSerializer.cs @@ -42,22 +42,23 @@ namespace Newtonsoft.Json /// public class JsonSerializer { - #region Properties - private TypeNameHandling _typeNameHandling; - private FormatterAssemblyStyle _typeNameAssemblyFormat; - private PreserveReferencesHandling _preserveReferencesHandling; - private ReferenceLoopHandling _referenceLoopHandling; - private MissingMemberHandling _missingMemberHandling; - private ObjectCreationHandling _objectCreationHandling; - private NullValueHandling _nullValueHandling; - private DefaultValueHandling _defaultValueHandling; - private ConstructorHandling _constructorHandling; - private JsonConverterCollection _converters; - private IContractResolver _contractResolver; + #region Properties_binder + internal TypeNameHandling _typeNameHandling; + internal FormatterAssemblyStyle _typeNameAssemblyFormat; + internal PreserveReferencesHandling _preserveReferencesHandling; + internal ReferenceLoopHandling _referenceLoopHandling; + internal MissingMemberHandling _missingMemberHandling; + internal ObjectCreationHandling _objectCreationHandling; + internal NullValueHandling _nullValueHandling; + internal DefaultValueHandling _defaultValueHandling; + internal ConstructorHandling _constructorHandling; + internal JsonConverterCollection _converters; + internal IContractResolver _contractResolver; + internal ITraceWriter _traceWriter; + internal SerializationBinder _binder; + internal StreamingContext _context; private IReferenceResolver _referenceResolver; - private ITraceWriter _traceWriter; - private SerializationBinder _binder; - private StreamingContext _context; + private Formatting? _formatting; private DateFormatHandling? _dateFormatHandling; private DateTimeZoneHandling? _dateTimeZoneHandling; @@ -82,13 +83,7 @@ namespace Newtonsoft.Json /// public virtual IReferenceResolver ReferenceResolver { - get - { - if (_referenceResolver == null) - _referenceResolver = new DefaultReferenceResolver(); - - return _referenceResolver; - } + get { return GetReferenceResolver(); } set { if (value == null) @@ -291,14 +286,8 @@ namespace Newtonsoft.Json /// public virtual IContractResolver ContractResolver { - get - { - if (_contractResolver == null) - _contractResolver = DefaultContractResolver.Instance; - - return _contractResolver; - } - set { _contractResolver = value; } + get { return _contractResolver; } + set { _contractResolver = value ?? DefaultContractResolver.Instance; } } /// @@ -448,6 +437,9 @@ namespace Newtonsoft.Json _typeNameHandling = JsonSerializerSettings.DefaultTypeNameHandling; _context = JsonSerializerSettings.DefaultContext; _binder = DefaultSerializationBinder.Instance; + + _culture = JsonSerializerSettings.DefaultCulture; + _contractResolver = DefaultContractResolver.Instance; } /// @@ -769,6 +761,14 @@ namespace Newtonsoft.Json jsonWriter.Culture = previousCulture; } + internal IReferenceResolver GetReferenceResolver() + { + if (_referenceResolver == null) + _referenceResolver = new DefaultReferenceResolver(); + + return _referenceResolver; + } + internal JsonConverter GetMatchingConverter(Type type) { return GetMatchingConverter(_converters, type); diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index a744dd1f..0666cca4 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -78,7 +78,7 @@ namespace Newtonsoft.Json _reader = reader; _lineNumber = 1; - _chars = new char[2049]; + _chars = new char[1025]; } #if DEBUG @@ -92,7 +92,7 @@ namespace Newtonsoft.Json { if (_buffer == null) { - _buffer = new StringBuffer(2048); + _buffer = new StringBuffer(1025); } else { @@ -153,7 +153,7 @@ namespace Newtonsoft.Json dateParseHandling = _dateParseHandling; object dt; - if (JsonConvert.TryParseDateTime(text, dateParseHandling, DateTimeZoneHandling, out dt)) + if (DateTimeUtils.TryParseDateTime(text, dateParseHandling, DateTimeZoneHandling, out dt)) { SetToken(JsonToken.Date, dt); return; diff --git a/Src/Newtonsoft.Json/JsonTextWriter.cs b/Src/Newtonsoft.Json/JsonTextWriter.cs index a3a41f7a..a14e0960 100644 --- a/Src/Newtonsoft.Json/JsonTextWriter.cs +++ b/Src/Newtonsoft.Json/JsonTextWriter.cs @@ -48,6 +48,7 @@ namespace Newtonsoft.Json private char _quoteChar; private bool _quoteName; private bool[] _charEscapeFlags; + private char[] _writeBuffer; private Base64Encoder Base64Encoder { @@ -373,7 +374,7 @@ namespace Newtonsoft.Json public override void WriteValue(int value) { InternalWriteValue(JsonToken.Integer); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Integer); + WriteIntegerValue(value); } /// @@ -384,7 +385,7 @@ namespace Newtonsoft.Json public override void WriteValue(uint value) { InternalWriteValue(JsonToken.Integer); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Integer); + WriteIntegerValue(value); } /// @@ -394,7 +395,7 @@ namespace Newtonsoft.Json public override void WriteValue(long value) { InternalWriteValue(JsonToken.Integer); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Integer); + WriteIntegerValue(value); } /// @@ -405,7 +406,7 @@ namespace Newtonsoft.Json public override void WriteValue(ulong value) { InternalWriteValue(JsonToken.Integer); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Integer); + WriteIntegerValue(value); } /// @@ -479,7 +480,7 @@ namespace Newtonsoft.Json public override void WriteValue(short value) { InternalWriteValue(JsonToken.Integer); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Integer); + WriteIntegerValue(value); } /// @@ -490,7 +491,7 @@ namespace Newtonsoft.Json public override void WriteValue(ushort value) { InternalWriteValue(JsonToken.Integer); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Integer); + WriteIntegerValue(value); } /// @@ -510,7 +511,7 @@ namespace Newtonsoft.Json public override void WriteValue(byte value) { InternalWriteValue(JsonToken.Integer); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Integer); + WriteIntegerValue(value); } /// @@ -521,7 +522,7 @@ namespace Newtonsoft.Json public override void WriteValue(sbyte value) { InternalWriteValue(JsonToken.Integer); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Integer); + WriteIntegerValue(value); } /// @@ -541,10 +542,25 @@ namespace Newtonsoft.Json public override void WriteValue(DateTime value) { InternalWriteValue(JsonToken.Date); - value = JsonConvert.EnsureDateTime(value, DateTimeZoneHandling); - _writer.Write(_quoteChar); - JsonConvert.WriteDateTimeString(_writer, value, DateFormatHandling, DateFormatString, Culture); - _writer.Write(_quoteChar); + value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling); + + if (string.IsNullOrEmpty(DateFormatString)) + { + EnsureWriteBuffer(); + + int pos = 0; + _writeBuffer[pos++] = _quoteChar; + pos = DateTimeUtils.WriteDateTimeString(_writeBuffer, pos, value, null, value.Kind, DateFormatHandling); + _writeBuffer[pos++] = _quoteChar; + + _writer.Write(_writeBuffer, 0, pos); + } + else + { + _writer.Write(_quoteChar); + _writer.Write(value.ToString(DateFormatString, Culture)); + _writer.Write(_quoteChar); + } } /// @@ -575,9 +591,24 @@ namespace Newtonsoft.Json public override void WriteValue(DateTimeOffset value) { InternalWriteValue(JsonToken.Date); - _writer.Write(_quoteChar); - JsonConvert.WriteDateTimeOffsetString(_writer, value, DateFormatHandling, DateFormatString, Culture); - _writer.Write(_quoteChar); + + if (string.IsNullOrEmpty(DateFormatString)) + { + EnsureWriteBuffer(); + + int pos = 0; + _writeBuffer[pos++] = _quoteChar; + pos = DateTimeUtils.WriteDateTimeString(_writeBuffer, pos, (DateFormatHandling == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, DateFormatHandling); + _writeBuffer[pos++] = _quoteChar; + + _writer.Write(_writeBuffer, 0, pos); + } + else + { + _writer.Write(_quoteChar); + _writer.Write(value.ToString(DateFormatString, Culture)); + _writer.Write(_quoteChar); + } } #endif @@ -642,5 +673,93 @@ namespace Newtonsoft.Json _writer.Write(ws); } + + private void EnsureWriteBuffer() + { + if (_writeBuffer == null) + _writeBuffer = new char[64]; + } + + private void WriteIntegerValue(int value) + { + EnsureWriteBuffer(); + + if (value >= 0 && value <= 9) + { + _writer.Write((char)(48 + value)); + } + else + { + int length = 0; + + uint uvalue = (value < 0) ? (uint)-value : (uint)value; + + do + { + _writeBuffer[length++] = (char)(48 + (uvalue % 10)); + uvalue /= 10; + } while (uvalue != 0); + + if (value < 0) + _writeBuffer[length++] = '-'; + + Array.Reverse(_writeBuffer, 0, length); + + _writer.Write(_writeBuffer, 0, length); + } + } + + private void WriteIntegerValue(long value) + { + EnsureWriteBuffer(); + + if (value >= 0 && value <= 9) + { + _writer.Write((char)(48 + value)); + } + else + { + int length = 0; + + ulong uvalue = (value < 0) ? (ulong)-value : (ulong)value; + + do + { + _writeBuffer[length++] = (char)(48 + (uvalue % 10)); + uvalue /= 10; + } while (uvalue != 0); + + if (value < 0) + _writeBuffer[length++] = '-'; + + Array.Reverse(_writeBuffer, 0, length); + + _writer.Write(_writeBuffer, 0, length); + } + } + + private void WriteIntegerValue(ulong uvalue) + { + EnsureWriteBuffer(); + + if (uvalue <= 9) + { + _writer.Write((char)(48 + uvalue)); + } + else + { + int length = 0; + + do + { + _writeBuffer[length++] = (char)(48 + (uvalue % 10)); + uvalue /= 10; + } while (uvalue != 0); + + Array.Reverse(_writeBuffer, 0, length); + + _writer.Write(_writeBuffer, 0, length); + } + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 31b2b4d0..49296137 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -572,7 +572,7 @@ namespace Newtonsoft.Json throw JsonWriterException.Create(this, "Unexpected token when reading date constructor. Expected Integer, got " + reader.TokenType, null); long ticks = (long)reader.Value; - DateTime date = JsonConvert.ConvertJavaScriptTicksToDateTime(ticks); + DateTime date = DateTimeUtils.ConvertJavaScriptTicksToDateTime(ticks); if (!reader.Read()) throw JsonWriterException.Create(this, "Unexpected end when reading date constructor.", null); diff --git a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs index 4f89cbf1..759020ce 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs @@ -396,7 +396,7 @@ namespace Newtonsoft.Json.Linq public override void WriteValue(DateTime value) { base.WriteValue(value); - value = JsonConvert.EnsureDateTime(value, DateTimeZoneHandling); + value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling); AddValue(value, JsonToken.Date); } diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj index 4e54d7e7..40cba141 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj @@ -113,6 +113,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj index 1acce3ec..9825915f 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj @@ -125,6 +125,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj index 0c007da1..bbab0fe9 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj @@ -57,6 +57,7 @@ Newtonsoft.Json.ruleset + true pdbonly @@ -122,6 +123,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj index b9922e63..ee32ed37 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj @@ -190,6 +190,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj index ea320862..00ac7103 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj @@ -190,6 +190,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj index 2252a7b2..faff3245 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -190,6 +190,7 @@ + diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs index 181171b7..ca6725d2 100644 --- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs @@ -92,6 +92,6 @@ using System.Security; // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] -[assembly: AssemblyFileVersion("5.0.1.16008")] +[assembly: AssemblyFileVersion("5.0.4.16021")] [assembly: CLSCompliant(true)] diff --git a/Src/Newtonsoft.Json/Serialization/JsonContract.cs b/Src/Newtonsoft.Json/Serialization/JsonContract.cs index 01472342..f3ce8cbe 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonContract.cs @@ -71,6 +71,7 @@ namespace Newtonsoft.Json.Serialization internal bool IsNullable; internal bool IsConvertable; internal bool IsSealed; + internal bool IsEnum; internal Type NonNullableUnderlyingType; internal ReadType InternalReadType; internal JsonContractType ContractType; @@ -286,7 +287,7 @@ namespace Newtonsoft.Json.Serialization CreatedType = NonNullableUnderlyingType; IsConvertable = ConvertUtils.IsConvertible(NonNullableUnderlyingType); - + IsEnum = NonNullableUnderlyingType.IsEnum(); if (NonNullableUnderlyingType == typeof(byte[])) { diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 63d00185..55c1019e 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -73,7 +73,7 @@ namespace Newtonsoft.Json.Serialization Type objectType = target.GetType(); - JsonContract contract = Serializer.ContractResolver.ResolveContract(objectType); + JsonContract contract = Serializer._contractResolver.ResolveContract(objectType); if (reader.TokenType == JsonToken.None) reader.Read(); @@ -128,7 +128,7 @@ namespace Newtonsoft.Json.Serialization if (type == null) return null; - return Serializer.ContractResolver.ResolveContract(type); + return Serializer._contractResolver.ResolveContract(type); } public object Deserialize(JsonReader reader, Type objectType, bool checkAdditionalContent) @@ -496,7 +496,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ if (reader.TokenType == JsonToken.PropertyName) throw JsonSerializationException.Create(reader, "Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName)); - newValue = Serializer.ReferenceResolver.ResolveReference(this, reference); + newValue = Serializer.GetReferenceResolver().ResolveReference(this, reference); if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue.GetType())), null); @@ -517,7 +517,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ ((member != null) ? member.TypeNameHandling : null) ?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null) ?? ((containerMember != null) ? containerMember.ItemTypeNameHandling : null) - ?? Serializer.TypeNameHandling; + ?? Serializer._typeNameHandling; if (resolvedTypeNameHandling != TypeNameHandling.None) { @@ -528,7 +528,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ Type specifiedType; try { - specifiedType = Serializer.Binder.BindToType(assemblyName, typeName); + specifiedType = Serializer._binder.BindToType(assemblyName, typeName); } catch (Exception ex) { @@ -697,7 +697,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ { JsonPrimitiveContract primitiveContract = (JsonPrimitiveContract)contract; - if (contract.NonNullableUnderlyingType.IsEnum()) + if (contract.IsEnum) { if (value is string) return Enum.Parse(contract.NonNullableUnderlyingType, value.ToString(), true); @@ -786,7 +786,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ property.PropertyContract = GetContractSafe(property.PropertyType); ObjectCreationHandling objectCreationHandling = - property.ObjectCreationHandling.GetValueOrDefault(Serializer.ObjectCreationHandling); + property.ObjectCreationHandling.GetValueOrDefault(Serializer._objectCreationHandling); if ((objectCreationHandling != ObjectCreationHandling.Replace) && (tokenType == JsonToken.StartArray || tokenType == JsonToken.StartObject) @@ -810,14 +810,14 @@ To fix this error either change the JSON to a {1} or change the deserialized typ } // test tokentype here because null might not be convertable to some types, e.g. ignoring null when applied to DateTime - if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && tokenType == JsonToken.Null) + if (property.NullValueHandling.GetValueOrDefault(Serializer._nullValueHandling) == NullValueHandling.Ignore && tokenType == JsonToken.Null) { reader.Skip(); return true; } // test tokentype here because default value might not be convertable to actual type, e.g. default of "" for DateTime - if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Ignore) + if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Ignore) && JsonReader.IsPrimitiveToken(tokenType) && MiscellaneousUtils.ValueEquals(reader.Value, property.GetResolvedDefaultValue())) { @@ -847,7 +847,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Read object reference Id '{0}' for {1}.".FormatWith(CultureInfo.InvariantCulture, id, value.GetType())), null); - Serializer.ReferenceResolver.AddReference(this, id, value); + Serializer.GetReferenceResolver().AddReference(this, id, value); } catch (Exception ex) { @@ -862,10 +862,10 @@ To fix this error either change the JSON to a {1} or change the deserialized typ private bool ShouldSetPropertyValue(JsonProperty property, object value) { - if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && value == null) + if (property.NullValueHandling.GetValueOrDefault(Serializer._nullValueHandling) == NullValueHandling.Ignore && value == null) return false; - if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Ignore) + if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Ignore) && MiscellaneousUtils.ValueEquals(value, property.GetResolvedDefaultValue())) return false; @@ -891,7 +891,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ return list; } - else if (contract.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor)) + else if (contract.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor)) { object list = contract.DefaultCreator(); @@ -919,7 +919,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ createdFromNonDefaultConstructor = true; return contract.CreateTemporaryDictionary(); } - else if (contract.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor)) + else if (contract.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor)) { object dictionary = contract.DefaultCreator(); @@ -945,7 +945,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Started deserializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null); - contract.InvokeOnDeserializing(value, Serializer.Context); + contract.InvokeOnDeserializing(value, Serializer._context); } private void OnDeserialized(JsonReader reader, JsonContract contract, object value) @@ -953,7 +953,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Finished deserializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null); - contract.InvokeOnDeserialized(value, Serializer.Context); + contract.InvokeOnDeserialized(value, Serializer._context); } private object PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, string id) @@ -990,12 +990,12 @@ To fix this error either change the JSON to a {1} or change the deserialized typ { // this is for correctly reading ISO and MS formatted dictionary keys if ((keyTypeCode == PrimitiveTypeCode.DateTime || keyTypeCode == PrimitiveTypeCode.DateTimeNullable) - && JsonConvert.TryParseDateTime(keyValue.ToString(), DateParseHandling.DateTime, reader.DateTimeZoneHandling, out keyValue)) + && DateTimeUtils.TryParseDateTime(keyValue.ToString(), DateParseHandling.DateTime, reader.DateTimeZoneHandling, out keyValue)) { } #if !NET20 else if ((keyTypeCode == PrimitiveTypeCode.DateTimeOffset || keyTypeCode == PrimitiveTypeCode.DateTimeOffsetNullable) - && JsonConvert.TryParseDateTime(keyValue.ToString(), DateParseHandling.DateTimeOffset, reader.DateTimeZoneHandling, out keyValue)) + && DateTimeUtils.TryParseDateTime(keyValue.ToString(), DateParseHandling.DateTimeOffset, reader.DateTimeZoneHandling, out keyValue)) { } #endif @@ -1316,7 +1316,7 @@ To fix this error either change the environment to be fully trusted, change the if (contract.ISerializableCreator == null) throw JsonSerializationException.Create(reader, "ISerializable type '{0}' does not have a valid constructor. To correctly implement ISerializable a constructor that takes SerializationInfo and StreamingContext parameters should be present.".FormatWith(CultureInfo.InvariantCulture, objectType)); - object createdObject = contract.ISerializableCreator(serializationInfo, Serializer.Context); + object createdObject = contract.ISerializableCreator(serializationInfo, Serializer._context); if (id != null) AddReference(reader, id, createdObject); @@ -1338,7 +1338,7 @@ To fix this error either change the environment to be fully trusted, change the throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)); if (contract.DefaultCreator != null && - (!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor)) + (!contract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor)) newObject = (IDynamicMetaObjectProvider) contract.DefaultCreator(); else throw JsonSerializationException.Create(reader, "Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)); @@ -1459,7 +1459,7 @@ To fix this error either change the environment to be fully trusted, change the else if (!property.Writable && value != null) { // handle readonly collection/dictionary properties - JsonContract propertyContract = Serializer.ContractResolver.ResolveContract(property.PropertyType); + JsonContract propertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType); if (propertyContract.ContractType == JsonContractType.Array) { @@ -1565,7 +1565,7 @@ To fix this error either change the environment to be fully trusted, change the if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}.".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType)), null); - if (Serializer.MissingMemberHandling == MissingMemberHandling.Error) + if (Serializer._missingMemberHandling == MissingMemberHandling.Error) throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name)); reader.Skip(); @@ -1648,7 +1648,7 @@ To fix this error either change the environment to be fully trusted, change the newObject = objectContract.OverrideConstructor.Invoke(null); } else if (objectContract.DefaultCreator != null && - (!objectContract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParametrizedConstructor == null)) + (!objectContract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParametrizedConstructor == null)) { // use the default constructor if it is... // public @@ -1674,7 +1674,7 @@ To fix this error either change the environment to be fully trusted, change the OnDeserializing(reader, contract, newObject); // only need to keep a track of properies presence if they are required or a value should be defaulted if missing - Dictionary propertiesPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer.DefaultValueHandling, DefaultValueHandling.Populate)) + Dictionary propertiesPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer._defaultValueHandling, DefaultValueHandling.Populate)) ? contract.Properties.ToDictionary(m => m, m => PropertyPresence.None) : null; @@ -1703,7 +1703,7 @@ To fix this error either change the environment to be fully trusted, change the if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType)), null); - if (Serializer.MissingMemberHandling == MissingMemberHandling.Error) + if (Serializer._missingMemberHandling == MissingMemberHandling.Error) throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name)); reader.Skip(); @@ -1775,7 +1775,7 @@ To fix this error either change the environment to be fully trusted, change the if (property.PropertyContract == null) property.PropertyContract = GetContractSafe(property.PropertyType); - if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Populate) && property.Writable) + if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate) && property.Writable) property.ValueProvider.SetValue(newObject, EnsureType(reader, property.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType)); break; case PropertyPresence.Null: diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index d6f32840..7e67c1fd 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -62,7 +62,7 @@ namespace Newtonsoft.Json.Serialization throw new ArgumentNullException("jsonWriter"); if (objectType != null) - _rootContract = Serializer.ContractResolver.ResolveContract(objectType); + _rootContract = Serializer._contractResolver.ResolveContract(objectType); SerializeValue(jsonWriter, value, GetContractSafe(value), null, null, null); } @@ -80,7 +80,7 @@ namespace Newtonsoft.Json.Serialization if (value == null) return null; - return Serializer.ContractResolver.ResolveContract(value.GetType()); + return Serializer._contractResolver.ResolveContract(value.GetType()); } private void SerializePrimitive(JsonWriter writer, object value, JsonPrimitiveContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) @@ -159,7 +159,7 @@ namespace Newtonsoft.Json.Serialization break; #endif case JsonContractType.Linq: - ((JToken) value).WriteTo(writer, (Serializer.Converters != null) ? Serializer.Converters.ToArray() : null); + ((JToken) value).WriteTo(writer, Serializer.Converters.ToArray()); break; } } @@ -196,24 +196,24 @@ namespace Newtonsoft.Json.Serialization if (isReference == null) { if (valueContract.ContractType == JsonContractType.Array) - isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays); + isReference = HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Arrays); else - isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects); + isReference = HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Objects); } if (!isReference.Value) return false; - return Serializer.ReferenceResolver.IsReferenced(this, value); + return Serializer.GetReferenceResolver().IsReferenced(this, value); } private bool ShouldWriteProperty(object memberValue, JsonProperty property) { - if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && + if (property.NullValueHandling.GetValueOrDefault(Serializer._nullValueHandling) == NullValueHandling.Ignore && memberValue == null) return false; - if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Ignore) + if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Ignore) && MiscellaneousUtils.ValueEquals(memberValue, property.GetResolvedDefaultValue())) return false; @@ -243,7 +243,7 @@ namespace Newtonsoft.Json.Serialization message += " for property '{0}'".FormatWith(CultureInfo.InvariantCulture, property.PropertyName); message += " with type '{0}'.".FormatWith(CultureInfo.InvariantCulture, value.GetType()); - switch (referenceLoopHandling.GetValueOrDefault(Serializer.ReferenceLoopHandling)) + switch (referenceLoopHandling.GetValueOrDefault(Serializer._referenceLoopHandling)) { case ReferenceLoopHandling.Error: throw JsonSerializationException.Create(null, writer.ContainerPath, message, null); @@ -280,7 +280,7 @@ namespace Newtonsoft.Json.Serialization { try { - string reference = Serializer.ReferenceResolver.GetReference(this, value); + string reference = Serializer.GetReferenceResolver().GetReference(this, value); return reference; } @@ -349,7 +349,7 @@ namespace Newtonsoft.Json.Serialization if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(null, writer.Path, "Started serializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null); - contract.InvokeOnSerializing(value, Serializer.Context); + contract.InvokeOnSerializing(value, Serializer._context); } private void OnSerialized(JsonWriter writer, JsonContract contract, object value) @@ -357,7 +357,7 @@ namespace Newtonsoft.Json.Serialization if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(null, writer.Path, "Finished serializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null); - contract.InvokeOnSerialized(value, Serializer.Context); + contract.InvokeOnSerialized(value, Serializer._context); } private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) @@ -405,7 +405,7 @@ namespace Newtonsoft.Json.Serialization if (!property.Ignored && property.Readable && ShouldSerialize(writer, property, value) && IsSpecified(writer, property, value)) { if (property.PropertyContract == null) - property.PropertyContract = Serializer.ContractResolver.ResolveContract(property.PropertyType); + property.PropertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType); memberValue = property.ValueProvider.GetValue(value); memberContract = (property.PropertyContract.IsSealed) ? property.PropertyContract : GetContractSafe(memberValue); @@ -443,7 +443,7 @@ namespace Newtonsoft.Json.Serialization { writer.WriteStartObject(); - bool isReference = ResolveIsReference(contract, member, collectionContract, containerProperty) ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects); + bool isReference = ResolveIsReference(contract, member, collectionContract, containerProperty) ?? HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Objects); if (isReference) { WriteReferenceIdProperty(writer, contract.UnderlyingType, value); @@ -467,7 +467,7 @@ namespace Newtonsoft.Json.Serialization private void WriteTypeProperty(JsonWriter writer, Type type) { - string typeName = ReflectionUtils.GetTypeName(type, Serializer.TypeNameAssemblyFormat, Serializer.Binder); + string typeName = ReflectionUtils.GetTypeName(type, Serializer._typeNameAssemblyFormat, Serializer._binder); if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(null, writer.Path, "Writing type name '{0}' for {1}.".FormatWith(CultureInfo.InvariantCulture, typeName, type)), null); @@ -647,7 +647,7 @@ namespace Newtonsoft.Json.Serialization private bool WriteStartArray(JsonWriter writer, object values, JsonArrayContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) { - bool isReference = ResolveIsReference(contract, member, containerContract, containerProperty) ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays); + bool isReference = ResolveIsReference(contract, member, containerContract, containerProperty) ?? HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Arrays); bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Arrays, contract, member, containerContract, containerProperty); bool writeMetadataObject = isReference || includeTypeDetails; @@ -667,7 +667,7 @@ namespace Newtonsoft.Json.Serialization } if (contract.ItemContract == null) - contract.ItemContract = Serializer.ContractResolver.ResolveContract(contract.CollectionItemType ?? typeof (object)); + contract.ItemContract = Serializer._contractResolver.ResolveContract(contract.CollectionItemType ?? typeof (object)); return writeMetadataObject; } @@ -690,7 +690,7 @@ To fix this error either change the environment to be fully trusted, change the WriteObjectStart(writer, value, contract, member, collectionContract, containerProperty); SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, new FormatterConverter()); - value.GetObjectData(serializationInfo, Serializer.Context); + value.GetObjectData(serializationInfo, Serializer._context); foreach (SerializationEntry serializationEntry in serializationInfo) { @@ -790,7 +790,7 @@ To fix this error either change the environment to be fully trusted, change the ((member != null) ? member.TypeNameHandling : null) ?? ((containerProperty != null) ? containerProperty.ItemTypeNameHandling : null) ?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null) - ?? Serializer.TypeNameHandling; + ?? Serializer._typeNameHandling; if (HasFlag(resolvedTypeNameHandling, typeNameHandlingFlag)) return true; @@ -829,10 +829,10 @@ To fix this error either change the environment to be fully trusted, change the WriteObjectStart(writer, underlyingDictionary, contract, member, collectionContract, containerProperty); if (contract.ItemContract == null) - contract.ItemContract = Serializer.ContractResolver.ResolveContract(contract.DictionaryValueType ?? typeof(object)); + contract.ItemContract = Serializer._contractResolver.ResolveContract(contract.DictionaryValueType ?? typeof(object)); if (contract.KeyContract == null) - contract.KeyContract = Serializer.ContractResolver.ResolveContract(contract.DictionaryKeyType ?? typeof(object)); + contract.KeyContract = Serializer._contractResolver.ResolveContract(contract.DictionaryKeyType ?? typeof(object)); int initialDepth = writer.Top; @@ -894,7 +894,7 @@ To fix this error either change the environment to be fully trusted, change the { escape = false; StringWriter sw = new StringWriter(CultureInfo.InvariantCulture); - JsonConvert.WriteDateTimeString(sw, (DateTime)key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture); + DateTimeUtils.WriteDateTimeString(sw, (DateTime)key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture); return sw.ToString(); } #if !NET20 @@ -902,7 +902,7 @@ To fix this error either change the environment to be fully trusted, change the { escape = false; StringWriter sw = new StringWriter(CultureInfo.InvariantCulture); - JsonConvert.WriteDateTimeOffsetString(sw, (DateTimeOffset)key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture); + DateTimeUtils.WriteDateTimeOffsetString(sw, (DateTimeOffset)key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture); return sw.ToString(); } #endif diff --git a/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs b/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs new file mode 100644 index 00000000..c7d395f9 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs @@ -0,0 +1,248 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; + +namespace Newtonsoft.Json.Utilities +{ + internal enum ParserTimeZone + { + Unspecified, + Utc, + LocalWestOfUtc, + LocalEastOfUtc + } + + internal struct DateTimeParser + { + static DateTimeParser() + { + Power10 = new[] { -1, 10, 100, 1000, 10000, 100000, 1000000 }; + + Lzyyyy = "yyyy".Length; + Lzyyyy_ = "yyyy-".Length; + Lzyyyy_MM = "yyyy-MM".Length; + Lzyyyy_MM_ = "yyyy-MM-".Length; + Lzyyyy_MM_dd = "yyyy-MM-dd".Length; + Lzyyyy_MM_ddT = "yyyy-MM-ddT".Length; + LzHH = "HH".Length; + LzHH_ = "HH:".Length; + LzHH_mm = "HH:mm".Length; + LzHH_mm_ = "HH:mm:".Length; + LzHH_mm_ss = "HH:mm:ss".Length; + Lz_ = "-".Length; + Lz_zz = "-zz".Length; + Lz_zz_ = "-zz:".Length; + Lz_zz_zz = "-zz:zz".Length; + } + + public int Year; + public int Month; + public int Day; + public int Hour; + public int Minute; + public int Second; + public int Fraction; + public int ZoneHour; + public int ZoneMinute; + public ParserTimeZone Zone; + + private string _text; + private int _length; + + private static readonly int[] Power10; + + private static readonly int Lzyyyy; + private static readonly int Lzyyyy_; + private static readonly int Lzyyyy_MM; + private static readonly int Lzyyyy_MM_; + private static readonly int Lzyyyy_MM_dd; + private static readonly int Lzyyyy_MM_ddT; + private static readonly int LzHH; + private static readonly int LzHH_; + private static readonly int LzHH_mm; + private static readonly int LzHH_mm_; + private static readonly int LzHH_mm_ss; + private static readonly int Lz_; + private static readonly int Lz_zz; + private static readonly int Lz_zz_; + private static readonly int Lz_zz_zz; + + private const short MaxFractionDigits = 7; + + public bool Parse(string text) + { + _text = text; + _length = text.Length; + + if (ParseDate(0) && ParseChar(Lzyyyy_MM_dd, 'T') && ParseTimeAndZoneAndWhitespace(Lzyyyy_MM_ddT)) + return true; + + return false; + } + + private bool ParseDate(int start) + { + return (Parse4Digit(start, out Year) + && 1 <= Year + && ParseChar(start + Lzyyyy, '-') + && Parse2Digit(start + Lzyyyy_, out Month) + && 1 <= Month + && Month <= 12 + && ParseChar(start + Lzyyyy_MM, '-') + && Parse2Digit(start + Lzyyyy_MM_, out Day) + && 1 <= Day + && Day <= DateTime.DaysInMonth(Year, Month)); + } + + private bool ParseTimeAndZoneAndWhitespace(int start) + { + return (ParseTime(ref start) && ParseZone(start)); + } + + private bool ParseTime(ref int start) + { + if (!(Parse2Digit(start, out Hour) + && Hour < 24 + && ParseChar(start + LzHH, ':') + && Parse2Digit(start + LzHH_, out Minute) + && Minute < 60 + && ParseChar(start + LzHH_mm, ':') + && Parse2Digit(start + LzHH_mm_, out Second) + && Second < 60)) + { + return false; + } + + start += LzHH_mm_ss; + if (ParseChar(start, '.')) + { + Fraction = 0; + int numberOfDigits = 0; + + while (++start < _length && numberOfDigits < MaxFractionDigits) + { + int digit = _text[start] - '0'; + if (digit < 0 || digit > 9) + break; + + Fraction = (Fraction*10) + digit; + + numberOfDigits++; + } + + if (numberOfDigits < MaxFractionDigits) + { + if (numberOfDigits == 0) + return false; + + Fraction *= Power10[MaxFractionDigits - numberOfDigits]; + } + } + return true; + } + + private bool ParseZone(int start) + { + if (start < _length) + { + char ch = _text[start]; + if (ch == 'Z' || ch == 'z') + { + Zone = ParserTimeZone.Utc; + start++; + } + else + { + if (start + 5 < _length + && Parse2Digit(start + Lz_, out ZoneHour) + && ZoneHour <= 99 + && ParseChar(start + Lz_zz, ':') + && Parse2Digit(start + Lz_zz_, out ZoneMinute) + && ZoneMinute <= 99) + { + switch (ch) + { + case '-': + Zone = ParserTimeZone.LocalWestOfUtc; + start += Lz_zz_zz; + break; + + case '+': + Zone = ParserTimeZone.LocalEastOfUtc; + start += Lz_zz_zz; + break; + } + } + } + } + + return (start == _length); + } + + private bool Parse4Digit(int start, out int num) + { + if (start + 3 < _length) + { + int digit1 = _text[start] - '0'; + int digit2 = _text[start + 1] - '0'; + int digit3 = _text[start + 2] - '0'; + int digit4 = _text[start + 3] - '0'; + if (0 <= digit1 && digit1 < 10 + && 0 <= digit2 && digit2 < 10 + && 0 <= digit3 && digit3 < 10 + && 0 <= digit4 && digit4 < 10) + { + num = (((((digit1*10) + digit2)*10) + digit3)*10) + digit4; + return true; + } + } + num = 0; + return false; + } + + private bool Parse2Digit(int start, out int num) + { + if (start + 1 < _length) + { + int digit1 = _text[start] - '0'; + int digit2 = _text[start + 1] - '0'; + if (0 <= digit1 && digit1 < 10 + && 0 <= digit2 && digit2 < 10) + { + num = (digit1*10) + digit2; + return true; + } + } + num = 0; + return false; + } + + private bool ParseChar(int start, char ch) + { + return (start < _length && _text[start] == ch); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs b/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs index 4d211d96..6e7a7a83 100644 --- a/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs @@ -1,4 +1,5 @@ #region License + // Copyright (c) 2007 James Newton-King // // Permission is hereby granted, free of charge, to any person @@ -21,9 +22,11 @@ // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. + #endregion using System; +using System.IO; using System.Xml; using System.Globalization; @@ -31,6 +34,22 @@ namespace Newtonsoft.Json.Utilities { internal static class DateTimeUtils { + internal static readonly long InitialJavaScriptDateTicks = 621355968000000000; + + private const int DaysPer100Years = 36524; + private const int DaysPer400Years = 146097; + private const int DaysPer4Years = 1461; + private const int DaysPerYear = 365; + private const long TicksPerDay = 864000000000L; + private static readonly int[] DaysToMonth365; + private static readonly int[] DaysToMonth366; + + static DateTimeUtils() + { + DaysToMonth365 = new[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; + DaysToMonth366 = new[] { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; + } + public static TimeSpan GetUtcOffset(this DateTime d) { #if NET20 @@ -56,5 +75,506 @@ namespace Newtonsoft.Json.Utilities } } #endif + + internal static DateTime EnsureDateTime(DateTime value, DateTimeZoneHandling timeZone) + { + switch (timeZone) + { + case DateTimeZoneHandling.Local: + value = SwitchToLocalTime(value); + break; + case DateTimeZoneHandling.Utc: + value = SwitchToUtcTime(value); + break; + case DateTimeZoneHandling.Unspecified: + value = new DateTime(value.Ticks, DateTimeKind.Unspecified); + break; + case DateTimeZoneHandling.RoundtripKind: + break; + default: + throw new ArgumentException("Invalid date time handling value."); + } + + return value; + } + + private static DateTime SwitchToLocalTime(DateTime value) + { + switch (value.Kind) + { + case DateTimeKind.Unspecified: + return new DateTime(value.Ticks, DateTimeKind.Local); + + case DateTimeKind.Utc: + return value.ToLocalTime(); + + case DateTimeKind.Local: + return value; + } + return value; + } + + private static DateTime SwitchToUtcTime(DateTime value) + { + switch (value.Kind) + { + case DateTimeKind.Unspecified: + return new DateTime(value.Ticks, DateTimeKind.Utc); + + case DateTimeKind.Utc: + return value; + + case DateTimeKind.Local: + return value.ToUniversalTime(); + } + return value; + } + + private static long ToUniversalTicks(DateTime dateTime) + { + if (dateTime.Kind == DateTimeKind.Utc) + return dateTime.Ticks; + + return ToUniversalTicks(dateTime, dateTime.GetUtcOffset()); + } + + private static long ToUniversalTicks(DateTime dateTime, TimeSpan offset) + { + // special case min and max value + // they never have a timezone appended to avoid issues + if (dateTime.Kind == DateTimeKind.Utc || dateTime == DateTime.MaxValue || dateTime == DateTime.MinValue) + return dateTime.Ticks; + + long ticks = dateTime.Ticks - offset.Ticks; + if (ticks > 3155378975999999999L) + return 3155378975999999999L; + + if (ticks < 0L) + return 0L; + + return ticks; + } + + internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, TimeSpan offset) + { + long universialTicks = ToUniversalTicks(dateTime, offset); + + return UniversialTicksToJavaScriptTicks(universialTicks); + } + + internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime) + { + return ConvertDateTimeToJavaScriptTicks(dateTime, true); + } + + internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, bool convertToUtc) + { + long ticks = (convertToUtc) ? ToUniversalTicks(dateTime) : dateTime.Ticks; + + return UniversialTicksToJavaScriptTicks(ticks); + } + + private static long UniversialTicksToJavaScriptTicks(long universialTicks) + { + long javaScriptTicks = (universialTicks - InitialJavaScriptDateTicks)/10000; + + return javaScriptTicks; + } + + internal static DateTime ConvertJavaScriptTicksToDateTime(long javaScriptTicks) + { + DateTime dateTime = new DateTime((javaScriptTicks*10000) + InitialJavaScriptDateTicks, DateTimeKind.Utc); + + return dateTime; + } + +#region Parse + + internal static bool TryParseDateIso(string text, DateParseHandling dateParseHandling, DateTimeZoneHandling dateTimeZoneHandling, out object dt) + { + DateTimeParser dateTimeParser = new DateTimeParser(); + if (!dateTimeParser.Parse(text)) + { + dt = null; + return false; + } + + DateTime d = new DateTime(dateTimeParser.Year, dateTimeParser.Month, dateTimeParser.Day, dateTimeParser.Hour, dateTimeParser.Minute, dateTimeParser.Second); + d = d.AddTicks(dateTimeParser.Fraction); + +#if !NET20 + if (dateParseHandling == DateParseHandling.DateTimeOffset) + { + TimeSpan offset; + + switch (dateTimeParser.Zone) + { + case ParserTimeZone.Utc: + offset = new TimeSpan(0L); + break; + case ParserTimeZone.LocalWestOfUtc: + offset = new TimeSpan(-dateTimeParser.ZoneHour, -dateTimeParser.ZoneMinute, 0); + break; + case ParserTimeZone.LocalEastOfUtc: + offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0); + break; + default: + offset = TimeZoneInfo.Local.GetUtcOffset(d); + break; + } + + long ticks = d.Ticks - offset.Ticks; + if (ticks < 0 || ticks > 3155378975999999999) + { + dt = null; + return false; + } + + dt = new DateTimeOffset(d, offset); + return true; + } + else +#endif + { + long ticks; + + switch (dateTimeParser.Zone) + { + case ParserTimeZone.Utc: + d = new DateTime(d.Ticks, DateTimeKind.Utc); + break; + + case ParserTimeZone.LocalWestOfUtc: + { + TimeSpan offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0); + ticks = d.Ticks + offset.Ticks; + if (ticks <= DateTime.MaxValue.Ticks) + { + d = new DateTime(ticks, DateTimeKind.Utc).ToLocalTime(); + } + else + { + ticks += d.GetUtcOffset().Ticks; + if (ticks > DateTime.MaxValue.Ticks) + ticks = DateTime.MaxValue.Ticks; + + d = new DateTime(ticks, DateTimeKind.Local); + } + break; + } + case ParserTimeZone.LocalEastOfUtc: + { + TimeSpan offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0); + ticks = d.Ticks - offset.Ticks; + if (ticks >= DateTime.MinValue.Ticks) + { + d = new DateTime(ticks, DateTimeKind.Utc).ToLocalTime(); + } + else + { + ticks += d.GetUtcOffset().Ticks; + if (ticks < DateTime.MinValue.Ticks) + ticks = DateTime.MinValue.Ticks; + + d = new DateTime(ticks, DateTimeKind.Local); + } + break; + } + } + + dt = EnsureDateTime(d, dateTimeZoneHandling); + return true; + } + } + + internal static bool TryParseDateTime(string s, DateParseHandling dateParseHandling, DateTimeZoneHandling dateTimeZoneHandling, out object dt) + { + if (s.Length > 0) + { + if (s[0] == '/') + { + if (s.StartsWith("/Date(", StringComparison.Ordinal) && s.EndsWith(")/", StringComparison.Ordinal)) + { + return TryParseDateMicrosoft(s, dateParseHandling, dateTimeZoneHandling, out dt); + } + } + else if (s.Length >= 19 && s.Length <= 40 && char.IsDigit(s[0]) && s[10] == 'T') + { + return TryParseDateIso(s, dateParseHandling, dateTimeZoneHandling, out dt); + } + } + + dt = null; + return false; + } + + private static bool TryParseDateMicrosoft(string text, DateParseHandling dateParseHandling, DateTimeZoneHandling dateTimeZoneHandling, out object dt) + { + string value = text.Substring(6, text.Length - 8); + DateTimeKind kind = DateTimeKind.Utc; + + int index = value.IndexOf('+', 1); + + if (index == -1) + index = value.IndexOf('-', 1); + + TimeSpan offset = TimeSpan.Zero; + + if (index != -1) + { + kind = DateTimeKind.Local; + offset = ReadOffset(value.Substring(index)); + value = value.Substring(0, index); + } + + long javaScriptTicks = long.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + + DateTime utcDateTime = ConvertJavaScriptTicksToDateTime(javaScriptTicks); + +#if !NET20 + if (dateParseHandling == DateParseHandling.DateTimeOffset) + { + dt = new DateTimeOffset(utcDateTime.Add(offset).Ticks, offset); + return true; + } + else +#endif + { + DateTime dateTime; + + switch (kind) + { + case DateTimeKind.Unspecified: + dateTime = DateTime.SpecifyKind(utcDateTime.ToLocalTime(), DateTimeKind.Unspecified); + break; + case DateTimeKind.Local: + dateTime = utcDateTime.ToLocalTime(); + break; + default: + dateTime = utcDateTime; + break; + } + + dt = EnsureDateTime(dateTime, dateTimeZoneHandling); + return true; + } + } + + private static TimeSpan ReadOffset(string offsetText) + { + bool negative = (offsetText[0] == '-'); + + int hours = int.Parse(offsetText.Substring(1, 2), NumberStyles.Integer, CultureInfo.InvariantCulture); + int minutes = 0; + if (offsetText.Length >= 5) + minutes = int.Parse(offsetText.Substring(3, 2), NumberStyles.Integer, CultureInfo.InvariantCulture); + + TimeSpan offset = TimeSpan.FromHours(hours) + TimeSpan.FromMinutes(minutes); + if (negative) + offset = offset.Negate(); + + return offset; + } +#endregion + +#region Write + internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format, string formatString, CultureInfo culture) + { + if (string.IsNullOrEmpty(formatString)) + { + char[] chars = new char[64]; + int pos = WriteDateTimeString(chars, 0, value, null, value.Kind, format); + writer.Write(chars, 0, pos); + } + else + { + writer.Write(value.ToString(formatString, culture)); + } + } + + internal static int WriteDateTimeString(char[] chars, int start, DateTime value, TimeSpan? offset, DateTimeKind kind, DateFormatHandling format) + { + int pos = start; + + if (format == DateFormatHandling.MicrosoftDateFormat) + { + TimeSpan o = offset ?? value.GetUtcOffset(); + + long javaScriptTicks = ConvertDateTimeToJavaScriptTicks(value, o); + + @"\/Date(".CopyTo(0, chars, pos, 7); + pos += 7; + + string ticksText = javaScriptTicks.ToString(CultureInfo.InvariantCulture); + ticksText.CopyTo(0, chars, pos, ticksText.Length); + pos += ticksText.Length; + + switch (kind) + { + case DateTimeKind.Unspecified: + if (value != DateTime.MaxValue && value != DateTime.MinValue) + pos = WriteDateTimeOffset(chars, pos, o, format); + break; + case DateTimeKind.Local: + pos = WriteDateTimeOffset(chars, pos, o, format); + break; + } + + @")\/".CopyTo(0, chars, pos, 3); + pos += 3; + } + else + { + pos = WriteDefaultIsoDate(chars, pos, value); + + switch (kind) + { + case DateTimeKind.Local: + pos = WriteDateTimeOffset(chars, pos, offset ?? value.GetUtcOffset(), format); + break; + case DateTimeKind.Utc: + chars[pos++] = 'Z'; + break; + } + } + + return pos; + } + + internal static int WriteDefaultIsoDate(char[] chars, int start, DateTime dt) + { + int length = 19; + + int year; + int month; + int day; + GetDateValues(dt, out year, out month, out day); + + CopyIntToCharArray(chars, start, year, 4); + chars[start + 4] = '-'; + CopyIntToCharArray(chars, start + 5, month, 2); + chars[start + 7] = '-'; + CopyIntToCharArray(chars, start + 8, day, 2); + chars[start + 10] = 'T'; + CopyIntToCharArray(chars, start + 11, dt.Hour, 2); + chars[start + 13] = ':'; + CopyIntToCharArray(chars, start + 14, dt.Minute, 2); + chars[start + 16] = ':'; + CopyIntToCharArray(chars, start + 17, dt.Second, 2); + + int fraction = (int)(dt.Ticks % 10000000L); + + if (fraction != 0) + { + int digits = 7; + while ((fraction%10) == 0) + { + digits--; + fraction /= 10; + } + + chars[start + 19] = '.'; + CopyIntToCharArray(chars, start + 20, fraction, digits); + + length += digits + 1; + } + + return start + length; + } + + private static void CopyIntToCharArray(char[] chars, int start, int value, int digits) + { + while (digits-- != 0) + { + chars[start + digits] = (char) ((value%10) + 48); + value /= 10; + } + } + + internal static int WriteDateTimeOffset(char[] chars, int start, TimeSpan offset, DateFormatHandling format) + { + chars[start++] = (offset.Ticks >= 0L) ? '+' : '-'; + + int absHours = Math.Abs(offset.Hours); + CopyIntToCharArray(chars, start, absHours, 2); + start += 2; + + if (format == DateFormatHandling.IsoDateFormat) + chars[start++] = ':'; + + int absMinutes = Math.Abs(offset.Minutes); + CopyIntToCharArray(chars, start, absMinutes, 2); + start += 2; + + return start; + } + +#if !NET20 + internal static void WriteDateTimeOffsetString(TextWriter writer, DateTimeOffset value, DateFormatHandling format, string formatString, CultureInfo culture) + { + if (string.IsNullOrEmpty(formatString)) + { + char[] chars = new char[64]; + int pos = WriteDateTimeString(chars, 0, (format == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, format); + + writer.Write(chars, 0, pos); + } + else + { + writer.Write(value.ToString(formatString, culture)); + } + } +#endif +#endregion + + private static void GetDateValues(DateTime td, out int year, out int month, out int day) + { + long ticks = td.Ticks; + // n = number of days since 1/1/0001 + int n = (int) (ticks/TicksPerDay); + // y400 = number of whole 400-year periods since 1/1/0001 + int y400 = n/DaysPer400Years; + // n = day number within 400-year period + n -= y400*DaysPer400Years; + // y100 = number of whole 100-year periods within 400-year period + int y100 = n/DaysPer100Years; + // Last 100-year period has an extra day, so decrement result if 4 + if (y100 == 4) + y100 = 3; + // n = day number within 100-year period + n -= y100*DaysPer100Years; + // y4 = number of whole 4-year periods within 100-year period + int y4 = n/DaysPer4Years; + // n = day number within 4-year period + n -= y4*DaysPer4Years; + // y1 = number of whole years within 4-year period + int y1 = n/DaysPerYear; + // Last year has an extra day, so decrement result if 4 + if (y1 == 4) + y1 = 3; + + year = y400*400 + y100*100 + y4*4 + y1 + 1; + + // n = day number within year + n -= y1*DaysPerYear; + + // Leap year calculation looks different from IsLeapYear since y1, y4, + // and y100 are relative to year 1, not year 0 + bool leapYear = y1 == 3 && (y4 != 24 || y100 == 3); + int[] days = leapYear ? DaysToMonth366 : DaysToMonth365; + // All months have less than 32 days, so n >> 5 is a good conservative + // estimate for the month + int m = n >> 5 + 1; + // m = 1-based month number + while (n >= days[m]) + { + m++; + } + + month = m; + + // Return 1-based day-of-month + day = n - days[m - 1] + 1; + } } -} +} \ No newline at end of file