From 4b7a94b5d92cdc6215bbf07064d2022d05707b9a Mon Sep 17 00:00:00 2001 From: Henrik Gedionsen Date: Wed, 16 Oct 2024 10:22:15 +0200 Subject: [PATCH 1/9] Move test setup out of benchmarked code --- .../Benchmarks/DeserializeBenchmarks.cs | 5 +++-- Src/Newtonsoft.Json.Tests/Benchmarks/SerializeBenchmarks.cs | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs b/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs index 289cc13fd..ed2442841 100644 --- a/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs +++ b/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs @@ -42,10 +42,11 @@ public class DeserializeBenchmarks { private static readonly string LargeJsonText; private static readonly string FloatArrayJson; + private static readonly string LargeJsonFilePath = TestFixtureBase.ResolvePath("large.json"); static DeserializeBenchmarks() { - LargeJsonText = System.IO.File.ReadAllText(TestFixtureBase.ResolvePath("large.json")); + LargeJsonText = System.IO.File.ReadAllText(LargeJsonFilePath); FloatArrayJson = new JArray(Enumerable.Range(0, 5000).Select(i => i * 1.1m)).ToString(Formatting.None); } @@ -59,7 +60,7 @@ public IList DeserializeLargeJsonText() [Benchmark] public IList DeserializeLargeJsonFile() { - using (var jsonFile = System.IO.File.OpenText(TestFixtureBase.ResolvePath("large.json"))) + using (var jsonFile = System.IO.File.OpenText(LargeJsonFilePath)) using (JsonTextReader jsonTextReader = new JsonTextReader(jsonFile)) { JsonSerializer serializer = new JsonSerializer(); diff --git a/Src/Newtonsoft.Json.Tests/Benchmarks/SerializeBenchmarks.cs b/Src/Newtonsoft.Json.Tests/Benchmarks/SerializeBenchmarks.cs index c086aebb3..715e463fb 100644 --- a/Src/Newtonsoft.Json.Tests/Benchmarks/SerializeBenchmarks.cs +++ b/Src/Newtonsoft.Json.Tests/Benchmarks/SerializeBenchmarks.cs @@ -42,6 +42,7 @@ namespace Newtonsoft.Json.Tests.Benchmarks public class SerializeBenchmarks { private static readonly IList LargeCollection; + private static readonly string LargeWriteJsonPath = TestFixtureBase.ResolvePath("largewrite.json"); static SerializeBenchmarks() { @@ -53,7 +54,7 @@ static SerializeBenchmarks() [Benchmark] public void SerializeLargeJsonFile() { - using (StreamWriter file = System.IO.File.CreateText(TestFixtureBase.ResolvePath("largewrite.json"))) + using (StreamWriter file = System.IO.File.CreateText(LargeWriteJsonPath)) { JsonSerializer serializer = new JsonSerializer(); serializer.Formatting = Formatting.Indented; From a2a64a0b15080e3121fbffcfaf81f1afda1ca656 Mon Sep 17 00:00:00 2001 From: Henrik Gedionsen Date: Thu, 17 Oct 2024 20:22:41 +0200 Subject: [PATCH 2/9] Avoid benchmarking System.IO.File & allocation & GC when possible --- .../Benchmarks/DeserializeBenchmarks.cs | 14 +++++--------- .../Benchmarks/SerializeBenchmarks.cs | 19 +++++-------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs b/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs index ed2442841..96561d3e0 100644 --- a/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs +++ b/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs @@ -27,13 +27,10 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; using BenchmarkDotNet.Attributes; using Newtonsoft.Json.Linq; -using Newtonsoft.Json; using Newtonsoft.Json.Tests.TestObjects; namespace Newtonsoft.Json.Tests.Benchmarks @@ -42,11 +39,11 @@ public class DeserializeBenchmarks { private static readonly string LargeJsonText; private static readonly string FloatArrayJson; - private static readonly string LargeJsonFilePath = TestFixtureBase.ResolvePath("large.json"); + private static readonly JsonSerializer Serializer = new(); static DeserializeBenchmarks() { - LargeJsonText = System.IO.File.ReadAllText(LargeJsonFilePath); + LargeJsonText = System.IO.File.ReadAllText(TestFixtureBase.ResolvePath("large.json")); FloatArrayJson = new JArray(Enumerable.Range(0, 5000).Select(i => i * 1.1m)).ToString(Formatting.None); } @@ -60,11 +57,10 @@ public IList DeserializeLargeJsonText() [Benchmark] public IList DeserializeLargeJsonFile() { - using (var jsonFile = System.IO.File.OpenText(LargeJsonFilePath)) + using StringReader jsonFile = new(LargeJsonText); using (JsonTextReader jsonTextReader = new JsonTextReader(jsonFile)) { - JsonSerializer serializer = new JsonSerializer(); - return serializer.Deserialize>(jsonTextReader); + return Serializer.Deserialize>(jsonTextReader); } } diff --git a/Src/Newtonsoft.Json.Tests/Benchmarks/SerializeBenchmarks.cs b/Src/Newtonsoft.Json.Tests/Benchmarks/SerializeBenchmarks.cs index 715e463fb..c4c37386e 100644 --- a/Src/Newtonsoft.Json.Tests/Benchmarks/SerializeBenchmarks.cs +++ b/Src/Newtonsoft.Json.Tests/Benchmarks/SerializeBenchmarks.cs @@ -25,16 +25,9 @@ #if HAVE_BENCHMARKS -using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; using BenchmarkDotNet.Attributes; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json; using Newtonsoft.Json.Tests.TestObjects; namespace Newtonsoft.Json.Tests.Benchmarks @@ -42,7 +35,9 @@ namespace Newtonsoft.Json.Tests.Benchmarks public class SerializeBenchmarks { private static readonly IList LargeCollection; - private static readonly string LargeWriteJsonPath = TestFixtureBase.ResolvePath("largewrite.json"); + private static readonly MemoryStream ReusedMemoryStream = new(); + private static readonly StreamWriter JsonFile = new(ReusedMemoryStream); + private static readonly JsonSerializer Serializer = new() { Formatting = Formatting.Indented }; static SerializeBenchmarks() { @@ -54,12 +49,8 @@ static SerializeBenchmarks() [Benchmark] public void SerializeLargeJsonFile() { - using (StreamWriter file = System.IO.File.CreateText(LargeWriteJsonPath)) - { - JsonSerializer serializer = new JsonSerializer(); - serializer.Formatting = Formatting.Indented; - serializer.Serialize(file, LargeCollection); - } + ReusedMemoryStream.Seek(0, SeekOrigin.Begin); + Serializer.Serialize(JsonFile, LargeCollection); } } } From 6956dda911dd220dddd04a0b553c59746e37752d Mon Sep 17 00:00:00 2001 From: Henrik Gedionsen Date: Thu, 17 Oct 2024 20:24:11 +0200 Subject: [PATCH 3/9] Added DeserializeDateTimeList benchmark --- .../Benchmarks/DeserializeBenchmarks.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs b/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs index 96561d3e0..0e3cf3451 100644 --- a/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs +++ b/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs @@ -39,6 +39,7 @@ public class DeserializeBenchmarks { private static readonly string LargeJsonText; private static readonly string FloatArrayJson; + private static readonly string DateArrayJson; private static readonly JsonSerializer Serializer = new(); static DeserializeBenchmarks() @@ -46,6 +47,8 @@ static DeserializeBenchmarks() LargeJsonText = System.IO.File.ReadAllText(TestFixtureBase.ResolvePath("large.json")); FloatArrayJson = new JArray(Enumerable.Range(0, 5000).Select(i => i * 1.1m)).ToString(Formatting.None); + DateTime time = new(1969, 7, 20, 2, 56, 15, DateTimeKind.Utc); + DateArrayJson = new JArray(Enumerable.Range(0, 5000).Select(i => time.AddDays(i))).ToString(Formatting.None); } [Benchmark] @@ -75,6 +78,11 @@ public IList DeserializeDecimalList() { return JsonConvert.DeserializeObject>(FloatArrayJson); } + [Benchmark] + public IList DeserializeDateTimeList() + { + return JsonConvert.DeserializeObject>(DateArrayJson); + } } } From 1750bb3004d1b3087ef1e586dcddd5e2eb4a60d0 Mon Sep 17 00:00:00 2001 From: Henrik Gedionsen Date: Thu, 17 Oct 2024 23:05:59 +0200 Subject: [PATCH 4/9] Fix tests when running in da-DK locale --- Src/Newtonsoft.Json.Tests/Issues/Issue2768.cs | 8 ++++---- Src/Newtonsoft.Json.Tests/JsonConvertTest.cs | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2768.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2768.cs index 6681c2a73..4580ffa6b 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue2768.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2768.cs @@ -71,7 +71,7 @@ public void Test_Deserialize() { decimal d = JsonConvert.DeserializeObject("0.0"); - Assert.AreEqual("0.0", d.ToString()); + Assert.AreEqual("0.0", d.ToString(CultureInfo.InvariantCulture)); } [Test] @@ -79,7 +79,7 @@ public void Test_Deserialize_Negative() { decimal d = JsonConvert.DeserializeObject("-0.0"); - Assert.AreEqual("0.0", d.ToString()); + Assert.AreEqual("0.0", d.ToString(CultureInfo.InvariantCulture)); } [Test] @@ -95,7 +95,7 @@ public void Test_Deserialize_MultipleTrailingZeroes() { decimal d = JsonConvert.DeserializeObject("0.00"); - Assert.AreEqual("0.00", d.ToString()); + Assert.AreEqual("0.00", d.ToString(CultureInfo.InvariantCulture)); } [Test] @@ -127,7 +127,7 @@ public void ParseJsonDecimal() } } - Assert.AreEqual("0.0", parsedValue.ToString()); + Assert.AreEqual("0.0", parsedValue?.ToString(CultureInfo.InvariantCulture)); } [Test] diff --git a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs index 2611929a2..655066445 100644 --- a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs @@ -778,7 +778,7 @@ public void WriteDateTime() Assert.AreEqual(@"\/Date(253402300799999)\/", result.MsDateUtc); DateTime year2000local = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Local); - string localToUtcDate = year2000local.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK"); + string localToUtcDate = year2000local.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK", CultureInfo.InvariantCulture); result = TestDateTime("DateTime Local", year2000local); Assert.AreEqual("2000-01-01T01:01:01" + GetOffset(year2000local, DateFormatHandling.IsoDateFormat), result.IsoDateRoundtrip); @@ -791,7 +791,7 @@ public void WriteDateTime() 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"); + localToUtcDate = millisecondsLocal.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK", CultureInfo.InvariantCulture); result = TestDateTime("DateTime Local with milliseconds", millisecondsLocal); Assert.AreEqual("2000-01-01T01:01:01.999" + GetOffset(millisecondsLocal, DateFormatHandling.IsoDateFormat), result.IsoDateRoundtrip); @@ -804,7 +804,7 @@ public void WriteDateTime() Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + @")\/", result.MsDateUtc); DateTime ticksLocal = new DateTime(636556897826822481, DateTimeKind.Local); - localToUtcDate = ticksLocal.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK"); + localToUtcDate = ticksLocal.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK", CultureInfo.InvariantCulture); result = TestDateTime("DateTime Local with ticks", ticksLocal); Assert.AreEqual("2018-03-03T16:03:02.6822481" + GetOffset(ticksLocal, DateFormatHandling.IsoDateFormat), result.IsoDateRoundtrip); @@ -829,7 +829,7 @@ public void WriteDateTime() 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"); + string utcTolocalDate = year2000Utc.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture); result = TestDateTime("DateTime Utc", year2000Utc); Assert.AreEqual("2000-01-01T01:01:01Z", result.IsoDateRoundtrip); @@ -842,7 +842,7 @@ public void WriteDateTime() Assert.AreEqual(@"\/Date(946688461000)\/", result.MsDateUtc); DateTime unixEpoc = new DateTime(621355968000000000, DateTimeKind.Utc); - utcTolocalDate = unixEpoc.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ss"); + utcTolocalDate = unixEpoc.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture); result = TestDateTime("DateTime Unix Epoc", unixEpoc); Assert.AreEqual("1970-01-01T00:00:00Z", result.IsoDateRoundtrip); From 549319e3ca5cc578ef6ea03f5d07fd705379f17f Mon Sep 17 00:00:00 2001 From: Henrik Gedionsen Date: Thu, 17 Oct 2024 23:10:38 +0200 Subject: [PATCH 5/9] Ignore Rider files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 810fdf33a..dbcfb2101 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ BenchmarkDotNet.Artifacts/ _ReSharper.* *.ReSharper.user *.resharper.user +*/.idea/* .vs/ .vscode/ *.lock.json From e974725ee58e77036d1acb3ab07a5807c7aef409 Mon Sep 17 00:00:00 2001 From: Henrik Gedionsen Date: Fri, 18 Oct 2024 12:46:07 +0200 Subject: [PATCH 6/9] Reduce the size of the internal struct DateTimeParser, as it is copied on stack --- .../Utilities/DateTimeParser.cs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs b/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs index 9addb98eb..d7066e20e 100644 --- a/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs +++ b/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs @@ -24,10 +24,11 @@ #endregion using System; +using System.Runtime.InteropServices; namespace Newtonsoft.Json.Utilities { - internal enum ParserTimeZone + internal enum ParserTimeZone : byte { Unspecified = 0, Utc = 1, @@ -35,6 +36,7 @@ internal enum ParserTimeZone LocalEastOfUtc = 3 } + [StructLayout(LayoutKind.Auto)] internal struct DateTimeParser { static DateTimeParser() @@ -56,15 +58,15 @@ static DateTimeParser() Lz_zz = "-zz".Length; } - public int Year; - public int Month; - public int Day; - public int Hour; - public int Minute; - public int Second; + public ushort Year; + public byte Month; + public byte Day; + public byte Hour; + public byte Minute; + public byte Second; public int Fraction; - public int ZoneHour; - public int ZoneMinute; + public byte ZoneHour; + public byte ZoneMinute; public ParserTimeZone Zone; private char[] _text; @@ -231,7 +233,7 @@ private bool ParseZone(int start) return (start == _end); } - private bool Parse4Digit(int start, out int num) + private bool Parse4Digit(int start, out ushort num) { if (start + 3 < _end) { @@ -244,7 +246,7 @@ private bool Parse4Digit(int start, out int num) && 0 <= digit3 && digit3 < 10 && 0 <= digit4 && digit4 < 10) { - num = (((((digit1 * 10) + digit2) * 10) + digit3) * 10) + digit4; + num = (ushort)((((((digit1 * 10) + digit2) * 10) + digit3) * 10) + digit4); return true; } } @@ -252,7 +254,7 @@ private bool Parse4Digit(int start, out int num) return false; } - private bool Parse2Digit(int start, out int num) + private bool Parse2Digit(int start, out byte num) { if (start + 1 < _end) { @@ -261,7 +263,7 @@ private bool Parse2Digit(int start, out int num) if (0 <= digit1 && digit1 < 10 && 0 <= digit2 && digit2 < 10) { - num = (digit1 * 10) + digit2; + num = (byte)((digit1 * 10) + digit2); return true; } } From 5a8ea585fe5239749c2b46232746649ef2c6dfed Mon Sep 17 00:00:00 2001 From: Henrik Gedionsen Date: Fri, 18 Oct 2024 17:20:21 +0200 Subject: [PATCH 7/9] Reuse calculated value --- Src/Newtonsoft.Json/Utilities/DateTimeParser.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs b/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs index d7066e20e..daf634d3c 100644 --- a/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs +++ b/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs @@ -256,10 +256,11 @@ private bool Parse4Digit(int start, out ushort num) private bool Parse2Digit(int start, out byte num) { - if (start + 1 < _end) + int end = start + 1; + if (end < _end) { int digit1 = _text[start] - '0'; - int digit2 = _text[start + 1] - '0'; + int digit2 = _text[end] - '0'; if (0 <= digit1 && digit1 < 10 && 0 <= digit2 && digit2 < 10) { From 0c1ebe6da53effcf2187a1cbc634e92e903a15f5 Mon Sep 17 00:00:00 2001 From: Henrik Gedionsen Date: Fri, 18 Oct 2024 18:23:12 +0200 Subject: [PATCH 8/9] Reverse the order of the 24:00:00 check, hour is very likely to be different than 24, minute & seconds are less likely to be 0 --- Src/Newtonsoft.Json/Utilities/DateTimeParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs b/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs index daf634d3c..3dea30913 100644 --- a/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs +++ b/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs @@ -132,7 +132,7 @@ private bool ParseTime(ref int start) && ParseChar(start + LzHH_mm, ':') && Parse2Digit(start + LzHH_mm_, out Second) && Second < 60 - && (Hour != 24 || (Minute == 0 && Second == 0)))) // hour can be 24 if minute/second is zero) + && ((Minute == 0 && Second == 0) || Hour != 24))) // hour can be 24 if minute/second is zero) { return false; } From 88bd7ccbd5291f184819b75916194922194cc8e9 Mon Sep 17 00:00:00 2001 From: Henrik Gedionsen Date: Mon, 21 Oct 2024 10:57:12 +0200 Subject: [PATCH 9/9] Lower level benchmark of DateTime parsing --- .../Benchmarks/DeserializeBenchmarks.cs | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs b/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs index 0e3cf3451..431b2fa65 100644 --- a/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs +++ b/Src/Newtonsoft.Json.Tests/Benchmarks/DeserializeBenchmarks.cs @@ -27,11 +27,13 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using BenchmarkDotNet.Attributes; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Tests.TestObjects; +using Newtonsoft.Json.Utilities; namespace Newtonsoft.Json.Tests.Benchmarks { @@ -40,15 +42,28 @@ public class DeserializeBenchmarks private static readonly string LargeJsonText; private static readonly string FloatArrayJson; private static readonly string DateArrayJson; + private static readonly StringReference[] DateTimeStringReferences; + private static readonly DateTimeOffset[] ParsedDateTimesArray; private static readonly JsonSerializer Serializer = new(); static DeserializeBenchmarks() { LargeJsonText = System.IO.File.ReadAllText(TestFixtureBase.ResolvePath("large.json")); - FloatArrayJson = new JArray(Enumerable.Range(0, 5000).Select(i => i * 1.1m)).ToString(Formatting.None); + const int count = 5000; + FloatArrayJson = new JArray(Enumerable.Range(0, count).Select(i => i * 1.1m)).ToString(Formatting.None); + var dates = new DateTime[count]; + DateTimeStringReferences = new StringReference[count]; + ParsedDateTimesArray = new DateTimeOffset[count]; DateTime time = new(1969, 7, 20, 2, 56, 15, DateTimeKind.Utc); - DateArrayJson = new JArray(Enumerable.Range(0, 5000).Select(i => time.AddDays(i))).ToString(Formatting.None); + for (int i = 0; i < count; i++) + { + DateTime dateTime = time.AddDays(i); + dates[i] = dateTime; + string dateTimeString = dateTime.ToString("O", CultureInfo.InvariantCulture); + DateTimeStringReferences[i] = new StringReference(dateTimeString.ToCharArray(), 0, dateTimeString.Length); + } + DateArrayJson = new JArray(dates).ToString(Formatting.None); } [Benchmark] @@ -78,11 +93,24 @@ public IList DeserializeDecimalList() { return JsonConvert.DeserializeObject>(FloatArrayJson); } + [Benchmark] public IList DeserializeDateTimeList() { return JsonConvert.DeserializeObject>(DateArrayJson); } + + [Benchmark] + public bool TryParseDateTimeOffsetIso() + { + bool success = true; + for (var index = 0; index < DateTimeStringReferences.Length; index++) + { + success &= DateTimeUtils.TryParseDateTimeOffsetIso(DateTimeStringReferences[index], out DateTimeOffset result); + ParsedDateTimesArray[index] = result; + } + return success; + } } }