Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/Newtonsoft.Json.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Newton-King <james@newtonking.com>2012-03-04 16:10:20 +0400
committerJames Newton-King <james@newtonking.com>2012-03-04 16:10:20 +0400
commitfd760e33898cc6b3badaf4a8b77a466139b87fac (patch)
treea57a49fd993993c3c9154dd7c096264a0e0f74d1
parentfb2a5998bc2e85bde77ab157c5d30eb4791d809f (diff)
-Added DateFormatHandling to control whether dates are written in the MS format or ISO format, with ISO as the default
-Added DateTimeZoneHandling to control reading and writing DateTime time zone details -Added reader/writer specific Formatting, DateFormatHandling and DateTimeZoneHandling to JsonSerializerSettings -Added feature of reader/writer specific settings to be set on JsonReader/JsonWriter when serializing -Added ReadAsDate to JsonReader -Added ReadAsString to JsonReader -Changed JsonTextReader to automatically read ISO strings as dates -Refactored ReadAsXXX methods and reduce code redundancy -Removed unused JsonDateTimeSerializationMode
-rw-r--r--Src/Newtonsoft.Json.Tests/Converters/DataSetConverterTests.cs10
-rw-r--r--Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs2
-rw-r--r--Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs40
-rw-r--r--Src/Newtonsoft.Json.Tests/JsonConvertTest.cs316
-rw-r--r--Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs8
-rw-r--r--Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs8
-rw-r--r--Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs8
-rw-r--r--Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs4
-rw-r--r--Src/Newtonsoft.Json.Tests/PerformanceTests.cs71
-rw-r--r--Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs2
-rw-r--r--Src/Newtonsoft.Json.Tests/Serialization/CamelCasePropertyNamesContractResolverTests.cs10
-rw-r--r--Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs2
-rw-r--r--Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs226
-rw-r--r--Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs2
-rw-r--r--Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs4
-rw-r--r--Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs6
-rw-r--r--Src/Newtonsoft.Json.Tests/TestFixtureBase.cs11
-rw-r--r--Src/Newtonsoft.Json/Bson/BsonReader.cs155
-rw-r--r--Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs10
-rw-r--r--Src/Newtonsoft.Json/Converters/JsonDateTimeSerializationMode.cs30
-rw-r--r--Src/Newtonsoft.Json/DateFormatHandling.cs8
-rw-r--r--Src/Newtonsoft.Json/DateTimeZoneHandling.cs28
-rw-r--r--Src/Newtonsoft.Json/Formatting.cs17
-rw-r--r--Src/Newtonsoft.Json/JsonConvert.cs175
-rw-r--r--Src/Newtonsoft.Json/JsonPosition.cs70
-rw-r--r--Src/Newtonsoft.Json/JsonReader.cs410
-rw-r--r--Src/Newtonsoft.Json/JsonSerializer.cs90
-rw-r--r--Src/Newtonsoft.Json/JsonSerializerSettings.cs37
-rw-r--r--Src/Newtonsoft.Json/JsonTextReader.cs393
-rw-r--r--Src/Newtonsoft.Json/JsonTextWriter.cs7
-rw-r--r--Src/Newtonsoft.Json/JsonValidatingReader.cs24
-rw-r--r--Src/Newtonsoft.Json/JsonWriter.cs68
-rw-r--r--Src/Newtonsoft.Json/Linq/JTokenReader.cs175
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj9
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj9
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj6
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj6
-rw-r--r--Src/Newtonsoft.Json/Newtonsoft.Json.csproj6
-rw-r--r--Src/Newtonsoft.Json/Properties/AssemblyInfo.cs2
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonContract.cs19
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs6
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs19
-rw-r--r--Src/Newtonsoft.Json/WriteState.cs41
43 files changed, 1726 insertions, 824 deletions
diff --git a/Src/Newtonsoft.Json.Tests/Converters/DataSetConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/DataSetConverterTests.cs
index 058072b..c333acc 100644
--- a/Src/Newtonsoft.Json.Tests/Converters/DataSetConverterTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Converters/DataSetConverterTests.cs
@@ -170,7 +170,7 @@ namespace Newtonsoft.Json.Tests.Converters
]
}";
- DataSet ds = JsonConvert.DeserializeObject<DataSet>(json, new IsoDateTimeConverter());
+ DataSet ds = JsonConvert.DeserializeObject<DataSet>(json);
Assert.IsNotNull(ds);
Assert.AreEqual(2, ds.Tables.Count);
@@ -187,7 +187,7 @@ namespace Newtonsoft.Json.Tests.Converters
Assert.AreEqual("TimeSpanCol", dt.Columns[3].ColumnName);
Assert.AreEqual(typeof(string), dt.Columns[3].DataType);
Assert.AreEqual("DateTimeCol", dt.Columns[4].ColumnName);
- Assert.AreEqual(typeof(string), dt.Columns[4].DataType);
+ Assert.AreEqual(typeof(DateTime), dt.Columns[4].DataType);
Assert.AreEqual("DecimalCol", dt.Columns[5].ColumnName);
Assert.AreEqual(typeof(double), dt.Columns[5].DataType);
@@ -270,7 +270,7 @@ namespace Newtonsoft.Json.Tests.Converters
""int32Col"": 1,
""booleanCol"": true,
""timeSpanCol"": ""10.22:10:15.1000000"",
- ""dateTimeCol"": ""\/Date(978048000000)\/"",
+ ""dateTimeCol"": ""2000-12-29T00:00:00Z"",
""decimalCol"": 64.0021
},
{
@@ -278,7 +278,7 @@ namespace Newtonsoft.Json.Tests.Converters
""int32Col"": 2,
""booleanCol"": true,
""timeSpanCol"": ""10.22:10:15.1000000"",
- ""dateTimeCol"": ""\/Date(978048000000)\/"",
+ ""dateTimeCol"": ""2000-12-29T00:00:00Z"",
""decimalCol"": 64.0021
}
],
@@ -288,7 +288,7 @@ namespace Newtonsoft.Json.Tests.Converters
""int32Col"": 1,
""booleanCol"": true,
""timeSpanCol"": ""10.22:10:15.1000000"",
- ""dateTimeCol"": ""\/Date(978048000000)\/"",
+ ""dateTimeCol"": ""2000-12-29T00:00:00Z"",
""decimalCol"": 64.0021
}
]
diff --git a/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs
index 0a614e2..fc4a686 100644
--- a/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs
@@ -97,7 +97,7 @@ namespace Newtonsoft.Json.Tests.Converters
""Int32Col"": 2147483647,
""BooleanCol"": true,
""TimeSpanCol"": ""10.22:10:15.1000000"",
- ""DateTimeCol"": ""\/Date(978048000000)\/"",
+ ""DateTimeCol"": ""2000-12-29T00:00:00Z"",
""DecimalCol"": 64.0021
}
]", json);
diff --git a/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs
index 3345423..e7ac34d 100644
--- a/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs
@@ -202,46 +202,6 @@ namespace Newtonsoft.Json.Tests.Converters
}
[Test]
- public void DeserializeUTC()
- {
- DateTimeTestClass c =
- JsonConvert.DeserializeObject<DateTimeTestClass>(@"{""PreField"":""Pre"",""DateTimeField"":""2008-12-12T12:12:12Z"",""DateTimeOffsetField"":""2008-12-12T12:12:12Z"",""PostField"":""Post""}", new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal });
-
- Assert.AreEqual(new DateTime(2008, 12, 12, 12, 12, 12, 0, DateTimeKind.Utc).ToLocalTime(), c.DateTimeField);
- Assert.AreEqual(new DateTimeOffset(2008, 12, 12, 12, 12, 12, 0, TimeSpan.Zero), c.DateTimeOffsetField);
- Assert.AreEqual("Pre", c.PreField);
- Assert.AreEqual("Post", c.PostField);
-
- DateTimeTestClass c2 =
- JsonConvert.DeserializeObject<DateTimeTestClass>(@"{""PreField"":""Pre"",""DateTimeField"":""2008-01-01T01:01:01Z"",""DateTimeOffsetField"":""2008-01-01T01:01:01Z"",""PostField"":""Post""}", new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal });
-
- Assert.AreEqual(new DateTime(2008, 1, 1, 1, 1, 1, 0, DateTimeKind.Utc).ToLocalTime(), c2.DateTimeField);
- Assert.AreEqual(new DateTimeOffset(2008, 1, 1, 1, 1, 1, 0, TimeSpan.Zero), c2.DateTimeOffsetField);
- Assert.AreEqual("Pre", c2.PreField);
- Assert.AreEqual("Post", c2.PostField);
- }
-
- [Test]
- public void NullableDeserializeUTC()
- {
- NullableDateTimeTestClass c =
- JsonConvert.DeserializeObject<NullableDateTimeTestClass>(@"{""PreField"":""Pre"",""DateTimeField"":""2008-12-12T12:12:12Z"",""DateTimeOffsetField"":""2008-12-12T12:12:12Z"",""PostField"":""Post""}", new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal });
-
- Assert.AreEqual(new DateTime(2008, 12, 12, 12, 12, 12, 0, DateTimeKind.Utc).ToLocalTime(), c.DateTimeField);
- Assert.AreEqual(new DateTimeOffset(2008, 12, 12, 12, 12, 12, 0, TimeSpan.Zero), c.DateTimeOffsetField);
- Assert.AreEqual("Pre", c.PreField);
- Assert.AreEqual("Post", c.PostField);
-
- NullableDateTimeTestClass c2 =
- JsonConvert.DeserializeObject<NullableDateTimeTestClass>(@"{""PreField"":""Pre"",""DateTimeField"":null,""DateTimeOffsetField"":null,""PostField"":""Post""}", new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal });
-
- Assert.AreEqual(null, c2.DateTimeField);
- Assert.AreEqual(null, c2.DateTimeOffsetField);
- Assert.AreEqual("Pre", c2.PreField);
- Assert.AreEqual("Post", c2.PostField);
- }
-
- [Test]
public void NullableDeserializeEmptyString()
{
string json = @"{""DateTimeField"":""""}";
diff --git a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs
index 91c11b9..f1348c2 100644
--- a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs
+++ b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs
@@ -24,6 +24,11 @@
#endregion
using System;
+using System.IO;
+using System.Runtime.Serialization;
+using System.Text;
+using System.Xml;
+using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Utilities;
using NUnit.Framework;
@@ -233,11 +238,17 @@ now brown cow?", '"', true);
Assert.AreEqual("1", JsonConvert.ToString(value));
value = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc);
- Assert.AreEqual(@"""\/Date(0)\/""", JsonConvert.ToString(value));
+ Assert.AreEqual(@"""1970-01-01T00:00:00Z""", JsonConvert.ToString(value));
+
+ value = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc);
+ Assert.AreEqual(@"""\/Date(0)\/""", JsonConvert.ToString((DateTime)value, DateFormatHandling.MicrosoftDateFormat, DateTimeZoneHandling.RoundtripKind));
#if !PocketPC && !NET20
value = new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, TimeSpan.Zero);
- Assert.AreEqual(@"""\/Date(0+0000)\/""", JsonConvert.ToString(value));
+ Assert.AreEqual(@"""1970-01-01T00:00:00+00:00""", JsonConvert.ToString(value));
+
+ value = new DateTimeOffset(JsonConvert.InitialJavaScriptDateTicks, TimeSpan.Zero);
+ Assert.AreEqual(@"""\/Date(0+0000)\/""", JsonConvert.ToString((DateTimeOffset)value, DateFormatHandling.MicrosoftDateFormat));
#endif
value = null;
@@ -305,9 +316,9 @@ now brown cow?", '"', true);
Assert.AreEqual("-1.0", JsonConvert.ToString(-1d));
Assert.AreEqual("1.01", JsonConvert.ToString(1.01));
Assert.AreEqual("1.001", JsonConvert.ToString(1.001));
- Assert.AreEqual(JsonConvert.PositiveInfinity, JsonConvert.ToString(double.PositiveInfinity));
- Assert.AreEqual(JsonConvert.NegativeInfinity, JsonConvert.ToString(double.NegativeInfinity));
- Assert.AreEqual(JsonConvert.NaN, JsonConvert.ToString(double.NaN));
+ Assert.AreEqual(JsonConvert.PositiveInfinity, JsonConvert.ToString(Double.PositiveInfinity));
+ Assert.AreEqual(JsonConvert.NegativeInfinity, JsonConvert.ToString(Double.NegativeInfinity));
+ Assert.AreEqual(JsonConvert.NaN, JsonConvert.ToString(Double.NaN));
}
[Test]
@@ -325,8 +336,8 @@ now brown cow?", '"', true);
Assert.AreEqual("1.0", JsonConvert.ToString(1m));
Assert.AreEqual("1.01", JsonConvert.ToString(1.01m));
Assert.AreEqual("1.001", JsonConvert.ToString(1.001m));
- Assert.AreEqual("79228162514264337593543950335.0", JsonConvert.ToString(decimal.MaxValue));
- Assert.AreEqual("-79228162514264337593543950335.0", JsonConvert.ToString(decimal.MinValue));
+ Assert.AreEqual("79228162514264337593543950335.0", JsonConvert.ToString(Decimal.MaxValue));
+ Assert.AreEqual("-79228162514264337593543950335.0", JsonConvert.ToString(Decimal.MinValue));
}
[Test]
@@ -338,5 +349,296 @@ now brown cow?", '"', true);
string json = JsonConvert.ToString(v);
Assert.AreEqual(@"""It's a good day\r\n\""sunshine\""""", json);
}
+
+ [Test]
+ public void WriteDateTime()
+ {
+ DateTimeResult result = null;
+
+ result = TestDateTime("DateTime Max", DateTime.MaxValue);
+ Assert.AreEqual("9999-12-31T23:59:59.9999999", result.IsoDateRoundtrip);
+ Assert.AreEqual("9999-12-31T23:59:59.9999999" + GetOffset(DateTime.MaxValue, DateFormatHandling.IsoDateFormat), result.IsoDateLocal);
+ Assert.AreEqual("9999-12-31T23:59:59.9999999", result.IsoDateUnspecified);
+ Assert.AreEqual("9999-12-31T23:59:59.9999999Z", result.IsoDateUtc);
+ Assert.AreEqual(@"\/Date(253402300799999)\/", result.MsDateRoundtrip);
+ Assert.AreEqual(@"\/Date(253402300799999" + GetOffset(DateTime.MaxValue, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal);
+ Assert.AreEqual(@"\/Date(253402300799999)\/", result.MsDateUnspecified);
+ 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");
+
+ result = TestDateTime("DateTime Local", year2000local);
+ Assert.AreEqual("2000-01-01T01:01:01" + GetOffset(year2000local, DateFormatHandling.IsoDateFormat), result.IsoDateRoundtrip);
+ 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);
+
+ DateTime millisecondsLocal = new DateTime(2000, 1, 1, 1, 1, 1, 999, DateTimeKind.Local);
+ localToUtcDate = millisecondsLocal.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK");
+
+ result = TestDateTime("DateTime Local with milliseconds", millisecondsLocal);
+ Assert.AreEqual("2000-01-01T01:01:01.999" + GetOffset(millisecondsLocal, DateFormatHandling.IsoDateFormat), result.IsoDateRoundtrip);
+ 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);
+
+ DateTime ticksLocal = new DateTime(634663873826822481, DateTimeKind.Local);
+ localToUtcDate = ticksLocal.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK");
+
+ result = TestDateTime("DateTime Local with ticks", ticksLocal);
+ Assert.AreEqual("2012-03-03T16:03:02.6822481" + GetOffset(ticksLocal, DateFormatHandling.IsoDateFormat), result.IsoDateRoundtrip);
+ 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);
+
+ DateTime year2000Unspecified = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Unspecified);
+
+ result = TestDateTime("DateTime Unspecified", year2000Unspecified);
+ Assert.AreEqual("2000-01-01T01:01:01", result.IsoDateRoundtrip);
+ 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);
+
+ DateTime year2000Utc = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc);
+ string utcTolocalDate = year2000Utc.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ss");
+
+ result = TestDateTime("DateTime Utc", year2000Utc);
+ Assert.AreEqual("2000-01-01T01:01:01Z", result.IsoDateRoundtrip);
+ Assert.AreEqual(utcTolocalDate + GetOffset(year2000Utc, 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(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(946688461000)\/", result.MsDateUtc);
+
+ DateTime unixEpoc = new DateTime(621355968000000000, DateTimeKind.Utc);
+ utcTolocalDate = unixEpoc.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ss");
+
+ result = TestDateTime("DateTime Unix Epoc", unixEpoc);
+ Assert.AreEqual("1970-01-01T00:00:00Z", result.IsoDateRoundtrip);
+ Assert.AreEqual(utcTolocalDate + GetOffset(unixEpoc, DateFormatHandling.IsoDateFormat), result.IsoDateLocal);
+ Assert.AreEqual("1970-01-01T00:00:00", result.IsoDateUnspecified);
+ 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(0)\/", result.MsDateUtc);
+
+ result = TestDateTime("DateTime Min", DateTime.MinValue);
+ Assert.AreEqual("0001-01-01T00:00:00", result.IsoDateRoundtrip);
+ Assert.AreEqual("0001-01-01T00:00:00" + GetOffset(DateTime.MinValue, DateFormatHandling.IsoDateFormat), result.IsoDateLocal);
+ Assert.AreEqual("0001-01-01T00:00:00", result.IsoDateUnspecified);
+ Assert.AreEqual("0001-01-01T00:00:00Z", result.IsoDateUtc);
+ Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateRoundtrip);
+ Assert.AreEqual(@"\/Date(-62135596800000" + GetOffset(DateTime.MinValue, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal);
+ Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateUnspecified);
+ Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateUtc);
+
+ result = TestDateTime("DateTime Default", default(DateTime));
+ Assert.AreEqual("0001-01-01T00:00:00", result.IsoDateRoundtrip);
+ Assert.AreEqual("0001-01-01T00:00:00" + GetOffset(default(DateTime), DateFormatHandling.IsoDateFormat), result.IsoDateLocal);
+ Assert.AreEqual("0001-01-01T00:00:00", result.IsoDateUnspecified);
+ Assert.AreEqual("0001-01-01T00:00:00Z", result.IsoDateUtc);
+ Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateRoundtrip);
+ Assert.AreEqual(@"\/Date(-62135596800000" + GetOffset(default(DateTime), DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal);
+ Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateUnspecified);
+ Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateUtc);
+
+#if !NET20
+ result = TestDateTime("DateTimeOffset TimeSpan Zero", new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.Zero));
+ Assert.AreEqual("2000-01-01T01:01:01+00:00", result.IsoDateRoundtrip);
+ Assert.AreEqual(@"\/Date(946688461000+0000)\/", result.MsDateRoundtrip);
+
+ result = TestDateTime("DateTimeOffset TimeSpan 1 hour", new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.FromHours(1)));
+ Assert.AreEqual("2000-01-01T01:01:01+01:00", result.IsoDateRoundtrip);
+ Assert.AreEqual(@"\/Date(946684861000+0100)\/", result.MsDateRoundtrip);
+
+ result = TestDateTime("DateTimeOffset TimeSpan 1.5 hour", new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.FromHours(1.5)));
+ Assert.AreEqual("2000-01-01T01:01:01+01:30", result.IsoDateRoundtrip);
+ Assert.AreEqual(@"\/Date(946683061000+0130)\/", result.MsDateRoundtrip);
+
+ result = TestDateTime("DateTimeOffset TimeSpan 13 hour", new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.FromHours(13)));
+ Assert.AreEqual("2000-01-01T01:01:01+13:00", result.IsoDateRoundtrip);
+ Assert.AreEqual(@"\/Date(946641661000+1300)\/", result.MsDateRoundtrip);
+
+ result = TestDateTime("DateTimeOffset TimeSpan with ticks", new DateTimeOffset(634663873826822481, TimeSpan.Zero));
+ Assert.AreEqual("2012-03-03T16:03:02.6822481+00:00", result.IsoDateRoundtrip);
+ Assert.AreEqual(@"\/Date(1330790582682+0000)\/", result.MsDateRoundtrip);
+
+ result = TestDateTime("DateTimeOffset Min", DateTimeOffset.MinValue);
+ Assert.AreEqual("0001-01-01T00:00:00+00:00", result.IsoDateRoundtrip);
+ Assert.AreEqual(@"\/Date(-62135596800000+0000)\/", result.MsDateRoundtrip);
+
+ result = TestDateTime("DateTimeOffset Max", DateTimeOffset.MaxValue);
+ Assert.AreEqual("9999-12-31T23:59:59.9999999+00:00", result.IsoDateRoundtrip);
+ Assert.AreEqual(@"\/Date(253402300799999+0000)\/", result.MsDateRoundtrip);
+
+ result = TestDateTime("DateTimeOffset Default", default(DateTimeOffset));
+ Assert.AreEqual("0001-01-01T00:00:00+00:00", result.IsoDateRoundtrip);
+ Assert.AreEqual(@"\/Date(-62135596800000+0000)\/", result.MsDateRoundtrip);
+#endif
+ }
+
+ public class DateTimeResult
+ {
+ public string IsoDateRoundtrip { get; set; }
+ public string IsoDateLocal { get; set; }
+ public string IsoDateUnspecified { get; set; }
+ public string IsoDateUtc { get; set; }
+
+ public string MsDateRoundtrip { get; set; }
+ public string MsDateLocal { get; set; }
+ public string MsDateUnspecified { get; set; }
+ public string MsDateUtc { get; set; }
+ }
+
+ private DateTimeResult TestDateTime<T>(string name, T value)
+ {
+ Console.WriteLine(name);
+
+ DateTimeResult result = new DateTimeResult();
+
+ result.IsoDateRoundtrip = TestDateTimeFormat(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.RoundtripKind);
+ if (value is DateTime)
+ {
+ result.IsoDateLocal = TestDateTimeFormat(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.Local);
+ result.IsoDateUnspecified = TestDateTimeFormat(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.Unspecified);
+ result.IsoDateUtc = TestDateTimeFormat(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.Utc);
+ }
+
+ result.MsDateRoundtrip = TestDateTimeFormat(value, DateFormatHandling.MicrosoftDateFormat, DateTimeZoneHandling.RoundtripKind);
+ if (value is DateTime)
+ {
+ result.MsDateLocal = TestDateTimeFormat(value, DateFormatHandling.MicrosoftDateFormat, DateTimeZoneHandling.Local);
+ result.MsDateUnspecified = TestDateTimeFormat(value, DateFormatHandling.MicrosoftDateFormat, DateTimeZoneHandling.Unspecified);
+ result.MsDateUtc = TestDateTimeFormat(value, DateFormatHandling.MicrosoftDateFormat, DateTimeZoneHandling.Utc);
+ }
+
+ TestDateTimeFormat(value, new IsoDateTimeConverter());
+
+ if (value is DateTime)
+ {
+ Console.WriteLine(XmlConvert.ToString((DateTime)(object)value, XmlDateTimeSerializationMode.RoundtripKind));
+ }
+ else
+ {
+ Console.WriteLine(XmlConvert.ToString((DateTimeOffset)(object)value));
+ }
+
+#if !NET20
+ MemoryStream ms = new MemoryStream();
+ DataContractSerializer s = new DataContractSerializer(typeof(T));
+ s.WriteObject(ms, value);
+ string json = Encoding.UTF8.GetString(ms.ToArray(), 0, Convert.ToInt32(ms.Length));
+ Console.WriteLine(json);
+#endif
+
+ Console.WriteLine();
+
+ return result;
+ }
+
+ private static string TestDateTimeFormat<T>(T value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling)
+ {
+ string date = null;
+
+ if (value is DateTime)
+ {
+ date = JsonConvert.ToString((DateTime)(object)value, format, timeZoneHandling);
+ }
+ else
+ {
+#if !NET20
+ date = JsonConvert.ToString((DateTimeOffset)(object)value, format);
+#endif
+ }
+
+ Console.WriteLine(format.ToString("g") + "-" + timeZoneHandling.ToString("g") + ": " + date);
+
+ if (timeZoneHandling == DateTimeZoneHandling.RoundtripKind)
+ {
+ T parsed = JsonConvert.DeserializeObject<T>(date);
+ try
+ {
+ Assert.AreEqual(value, parsed);
+ }
+ catch (Exception ex)
+ {
+ long valueTicks = GetTicks(value);
+ long parsedTicks = GetTicks(parsed);
+
+ valueTicks = (valueTicks/10000)*10000;
+
+ Assert.AreEqual(valueTicks, parsedTicks);
+ }
+ }
+
+ return date.Trim('"');
+ }
+
+ private static void TestDateTimeFormat<T>(T value, JsonConverter converter)
+ {
+ string date = Write(value, converter);
+
+ Console.WriteLine(converter.GetType().Name + ": " + date);
+
+ T parsed = Read<T>(date, converter);
+
+ try
+ {
+ Assert.AreEqual(value, parsed);
+ }
+ catch (Exception ex)
+ {
+ // JavaScript ticks aren't as precise, recheck after rounding
+ long valueTicks = GetTicks(value);
+ long parsedTicks = GetTicks(parsed);
+
+ valueTicks = (valueTicks / 10000) * 10000;
+
+ Assert.AreEqual(valueTicks, parsedTicks);
+ }
+ }
+
+ public static long GetTicks(object value)
+ {
+ return (value is DateTime) ? ((DateTime)value).Ticks : ((DateTimeOffset)value).Ticks;
+ }
+
+ public static string Write(object value, JsonConverter converter)
+ {
+ StringWriter sw = new StringWriter();
+ JsonTextWriter writer = new JsonTextWriter(sw);
+ converter.WriteJson(writer, value, null);
+
+ writer.Flush();
+ return sw.ToString();
+ }
+
+ public static T Read<T>(string text, JsonConverter converter)
+ {
+ JsonTextReader reader = new JsonTextReader(new StringReader(text));
+ reader.ReadAsString();
+
+ return (T)converter.ReadJson(reader, typeof(T), null, null);
+ }
}
} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
index 3488f99..173117b 100644
--- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
+++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
@@ -586,7 +586,7 @@ Parameter name: reader")]
}
[Test]
- [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected token when reading bytes: Boolean. Line 1, position 4.")]
+ [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading bytes. Unexpected token: Boolean. Line 1, position 4.")]
public void ReadBytesWithBadCharacter()
{
JsonReader reader = new JsonTextReader(new StringReader(@"true"));
@@ -1219,7 +1219,7 @@ bye", reader.Value);
#endif
[Test]
- [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected token when reading decimal: StartConstructor. Line 1, position 9.")]
+ [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading decimal. Unexpected token: StartConstructor. Line 1, position 9.")]
public void ReadAsDecimalBadContent()
{
JsonTextReader reader = new JsonTextReader(new StringReader(@"new Date()"));
@@ -1229,7 +1229,7 @@ bye", reader.Value);
}
[Test]
- [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected token when reading bytes: StartConstructor. Line 1, position 9.")]
+ [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading bytes. Unexpected token: StartConstructor. Line 1, position 9.")]
public void ReadAsBytesBadContent()
{
JsonTextReader reader = new JsonTextReader(new StringReader(@"new Date()"));
@@ -1239,7 +1239,7 @@ bye", reader.Value);
#if !NET20
[Test]
- [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected token when reading date: StartConstructor. Line 1, position 9.")]
+ [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading date. Unexpected token: StartConstructor. Line 1, position 9.")]
public void ReadAsDateTimeOffsetBadContent()
{
JsonTextReader reader = new JsonTextReader(new StringReader(@"new Date()"));
diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs
index 97323a1..ad1effc 100644
--- a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs
+++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs
@@ -25,10 +25,14 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.Serialization;
using System.Text;
+using System.Xml;
using NUnit.Framework;
using Newtonsoft.Json;
using System.IO;
+using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Tests
@@ -133,9 +137,9 @@ namespace Newtonsoft.Json.Tests
string expected;
#if !PocketPC && !NET20
- expected = @"[null,""c"",null,true,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1.1,null,1.1,null,1.1,null,""\/Date(0)\/"",null,""\/Date(0+0000)\/""]";
+ expected = @"[null,""c"",null,true,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1.1,null,1.1,null,1.1,null,""1970-01-01T00:00:00Z"",null,""1970-01-01T00:00:00+00:00""]";
#else
- expected = @"[null,""c"",null,true,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1.1,null,1.1,null,1.1,null,""\/Date(0)\/""]";
+ expected = @"[null,""c"",null,true,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1.1,null,1.1,null,1.1,null,""1970-01-01T00:00:00Z""]";
#endif
Assert.AreEqual(expected, json);
diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs
index 1a201ba..64136e6 100644
--- a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs
+++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs
@@ -135,7 +135,7 @@ namespace Newtonsoft.Json.Tests.Linq
}
[Test]
- [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading date. Expected date but got Boolean. Line 1, position 14.")]
+ [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading date. Unexpected token: Boolean. Line 1, position 14.")]
public void ReadAsDateTimeOffsetBoolean()
{
string json = @"{""Offset"":true}";
@@ -294,7 +294,7 @@ namespace Newtonsoft.Json.Tests.Linq
}
[Test]
- [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading bytes. Expected bytes but got Integer.")]
+ [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading bytes. Unexpected token: Integer.")]
public void ReadBytesFailure()
{
JObject o =
@@ -484,7 +484,7 @@ namespace Newtonsoft.Json.Tests.Linq
}
[Test]
- [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading integer. Expected a number but got Boolean. Line 1, position 12.")]
+ [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading integer. Unexpected token: Boolean. Line 1, position 12.")]
public void ReadAsInt32Boolean()
{
string json = @"{""Name"":true}";
@@ -543,7 +543,7 @@ namespace Newtonsoft.Json.Tests.Linq
}
[Test]
- [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading decimal. Expected a number but got Boolean. Line 1, position 12.")]
+ [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading decimal. Unexpected token: Boolean. Line 1, position 12.")]
public void ReadAsDecimalBoolean()
{
string json = @"{""Name"":true}";
diff --git a/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs
index 56ea70f..e717cb4 100644
--- a/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs
+++ b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs
@@ -349,13 +349,13 @@ keyword such as type of business.""
""Test3"": ""Test3Value"",
""Test4"": null
},
- ""\/Date(971136000000)\/"",
+ ""2000-10-10T00:00:00Z"",
55,
[
""1"",
2,
3.0,
- ""\/Date(-62030076711000)\/""
+ ""0004-05-06T07:08:09Z""
],
new ConstructorName(
""param1"",
diff --git a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
index 5b1d8ed..ca92859 100644
--- a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
+++ b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
@@ -39,8 +39,8 @@ namespace Newtonsoft.Json.Tests
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
@@ -56,12 +56,16 @@ namespace Newtonsoft.Json.Tests
private const string JsonText =
@"{""strings"":[null,""Markus egger ]><[, (2nd)"",null],""dictionary"":{""Val & asd1"":1,""Val2 & asd1"":3,""Val3 & asd1"":4},""Name"":""Rick"",""Now"":""\/Date(1262301136080+1300)\/"",""BigNumber"":34123123123.121,""Address1"":{""Street"":""fff Street"",""Phone"":""(503) 814-6335"",""Entered"":""\/Date(1264025536080+1300)\/""},""Addresses"":[{""Street"":""\u001farray<address"",""Phone"":""(503) 814-6335"",""Entered"":""\/Date(1262211136080+1300)\/""},{""Street"":""array 2 address"",""Phone"":""(503) 814-6335"",""Entered"":""\/Date(1262124736080+1300)\/""}]}";
+ private const string JsonIsoText =
+ @"{""strings"":[null,""Markus egger ]><[, (2nd)"",null],""dictionary"":{""Val & asd1"":1,""Val2 & asd1"":3,""Val3 & asd1"":4},""Name"":""Rick"",""Now"":""2012-02-25T19:55:50.6095676+13:00"",""BigNumber"":34123123123.121,""Address1"":{""Street"":""fff Street"",""Phone"":""(503) 814-6335"",""Entered"":""2012-02-24T18:55:50.6095676+13:00""},""Addresses"":[{""Street"":""\u001farray<address"",""Phone"":""(503) 814-6335"",""Entered"":""2012-02-24T18:55:50.6095676+13:00""},{""Street"":""array 2 address"",""Phone"":""(503) 814-6335"",""Entered"":""2012-02-24T18:55:50.6095676+13:00""}]}";
+
private const string SimpleJsonText =
@"{""Id"":2311,""Name"":""Simple-1"",""Address"":""Planet Earth"",""Scores"":[82,96,49,40,38,38,78,96,2,39]}";
public enum SerializeMethod
{
JsonNet,
+ JsonNetWithIsoConverter,
JsonNetBinary,
BinaryFormatter,
JavaScriptSerializer,
@@ -100,6 +104,7 @@ namespace Newtonsoft.Json.Tests
BenchmarkSerializeMethod(SerializeMethod.JavaScriptSerializer, value);
BenchmarkSerializeMethod(SerializeMethod.DataContractJsonSerializer, value);
BenchmarkSerializeMethod(SerializeMethod.JsonNet, value);
+ BenchmarkSerializeMethod(SerializeMethod.JsonNetWithIsoConverter, value);
BenchmarkSerializeMethod(SerializeMethod.JsonNetBinary, value);
}
@@ -109,6 +114,7 @@ namespace Newtonsoft.Json.Tests
BenchmarkDeserializeMethod<TestClass>(SerializeMethod.DataContractSerializer, XmlText);
BenchmarkDeserializeMethod<TestClass>(SerializeMethod.BinaryFormatter, MiscellaneousUtils.HexToBytes(BinaryFormatterHex));
DeserializeTests<TestClass>(JsonText);
+ BenchmarkDeserializeMethod<TestClass>(SerializeMethod.JsonNetWithIsoConverter, JsonIsoText);
BenchmarkDeserializeMethod<TestClass>(SerializeMethod.JsonNetBinary, MiscellaneousUtils.HexToBytes(BsonHex));
}
@@ -471,6 +477,9 @@ namespace Newtonsoft.Json.Tests
case SerializeMethod.JsonNet:
json = JsonConvert.SerializeObject(value);
break;
+ case SerializeMethod.JsonNetWithIsoConverter:
+ json = JsonConvert.SerializeObject(value, new IsoDateTimeConverter());
+ break;
case SerializeMethod.JsonNetBinary:
{
MemoryStream ms = new MemoryStream(Buffer);
@@ -538,7 +547,7 @@ namespace Newtonsoft.Json.Tests
Console.WriteLine();
}
- public T DeserializeJsonNet<T>(string json)
+ public T DeserializeJsonNet<T>(string json, bool isoDateTimeConverter)
{
Type type = typeof (T);
@@ -546,9 +555,11 @@ namespace Newtonsoft.Json.Tests
serializer.ObjectCreationHandling = Newtonsoft.Json.ObjectCreationHandling.Replace;
serializer.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore;
serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
+ if (isoDateTimeConverter)
+ serializer.Converters.Add(new IsoDateTimeConverter());
- return (T) serializer.Deserialize(new StringReader(json), type);
-
+ var value = (T) serializer.Deserialize(new StringReader(json), type);
+ return value;
//JsonTextReader reader = new JsonTextReader(new StringReader(JsonText));
//while (reader.Read())
//{
@@ -591,7 +602,9 @@ namespace Newtonsoft.Json.Tests
switch (method)
{
case SerializeMethod.JsonNet:
- return DeserializeJsonNet<T>((string) json);
+ return DeserializeJsonNet<T>((string)json, false);
+ case SerializeMethod.JsonNetWithIsoConverter:
+ return DeserializeJsonNet<T>((string)json, true);
case SerializeMethod.JsonNetBinary:
return DeserializeJsonNetBinary<T>((byte[]) json);
case SerializeMethod.BinaryFormatter:
@@ -689,6 +702,52 @@ namespace Newtonsoft.Json.Tests
return null;
}, "JObject.ToString");
}
+
+ [Test]
+ [Ignore]
+ public void NestedJToken()
+ {
+ Stopwatch sw;
+ for (int i = 10000; i <= 100000; i += 10000)
+ {
+ sw = new Stopwatch();
+ sw.Start();
+ JArray ija = new JArray();
+ JToken ijt = ija;
+ for (int j = 0; j < i; j++)
+ {
+ JArray temp = new JArray();
+ ija.Add(temp);
+ ija = temp;
+ }
+ ija.Add(1);
+ sw.Stop();
+ Console.WriteLine("Created a JToken of depth {0} (using OM) in {1} millis", i, sw.ElapsedMilliseconds);
+ }
+ }
+
+ [Test]
+ [Ignore]
+ public void NestedXElement()
+ {
+ Stopwatch sw;
+ for (int i = 10000; i <= 100000; i += 10000)
+ {
+ sw = new Stopwatch();
+ sw.Start();
+ XElement ija = new XElement("root");
+ XElement ijt = ija;
+ for (int j = 0; j < i; j++)
+ {
+ XElement temp = new XElement("child");
+ ija.Add(temp);
+ ija = temp;
+ }
+ ija.Add(1);
+ sw.Stop();
+ Console.WriteLine("Created a XElement of depth {0} (using OM) in {1} millis", i, sw.ElapsedMilliseconds);
+ }
+ }
}
public class LargeRecursiveTestClass
diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
index 4a503e7..e5c19f6 100644
--- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
+++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
@@ -72,5 +72,5 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.0.8.0")]
#if !PocketPC
-[assembly: AssemblyFileVersion("4.0.8.14625")]
+[assembly: AssemblyFileVersion("4.0.8.14704")]
#endif
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/CamelCasePropertyNamesContractResolverTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/CamelCasePropertyNamesContractResolverTests.cs
index b67a5cc..e59bc4e 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/CamelCasePropertyNamesContractResolverTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/CamelCasePropertyNamesContractResolverTests.cs
@@ -53,8 +53,8 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual(@"{
""name"": ""Name!"",
- ""birthDate"": ""\/Date(974764544000)\/"",
- ""lastModified"": ""\/Date(974764544000)\/""
+ ""birthDate"": ""2000-11-20T23:55:44Z"",
+ ""lastModified"": ""2000-11-20T23:55:44Z""
}", json);
Person deserializedPerson = JsonConvert.DeserializeObject<Person>(json, new JsonSerializerSettings
@@ -69,8 +69,8 @@ namespace Newtonsoft.Json.Tests.Serialization
json = JsonConvert.SerializeObject(person, Formatting.Indented);
Assert.AreEqual(@"{
""Name"": ""Name!"",
- ""BirthDate"": ""\/Date(974764544000)\/"",
- ""LastModified"": ""\/Date(974764544000)\/""
+ ""BirthDate"": ""2000-11-20T23:55:44Z"",
+ ""LastModified"": ""2000-11-20T23:55:44Z""
}", json);
}
@@ -160,7 +160,7 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual(@"{
""name"": ""Widget"",
- ""expiryDate"": ""\/Date(1292868060000)\/"",
+ ""expiryDate"": ""2010-12-20T18:01:00Z"",
""price"": 9.99,
""sizes"": [
""Small"",
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs
index eef6b5e..178e105 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs
@@ -70,7 +70,7 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual(@"{
""FirstName"": ""Maurice"",
""LastName"": ""Moss"",
- ""BirthDate"": ""\/Date(252291661000)\/""
+ ""BirthDate"": ""1977-12-30T01:01:01Z""
}", iPersonJson);
}
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
index 39b3103..d568eec 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
@@ -486,12 +486,12 @@ keyword such as type of business.""
string expected = sr.ReadToEnd();
- result = JsonConvert.SerializeObject(testDates);
+ result = JsonConvert.SerializeObject(testDates, new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat });
Assert.AreEqual(expected, result);
}
[Test]
- public void DateTimeOffset()
+ public void DateTimeOffsetIso()
{
List<DateTimeOffset> testDates = new List<DateTimeOffset>
{
@@ -502,6 +502,21 @@ keyword such as type of business.""
};
string result = JsonConvert.SerializeObject(testDates);
+ Assert.AreEqual(@"[""0100-01-01T01:01:01+00:00"",""2000-01-01T01:01:01+00:00"",""2000-01-01T01:01:01+13:00"",""2000-01-01T01:01:01-03:30""]", result);
+ }
+
+ [Test]
+ public void DateTimeOffsetMsAjax()
+ {
+ List<DateTimeOffset> testDates = new List<DateTimeOffset>
+ {
+ new DateTimeOffset(new DateTime(100, 1, 1, 1, 1, 1, DateTimeKind.Utc)),
+ new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.Zero),
+ new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.FromHours(13)),
+ new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.FromHours(-3.5)),
+ };
+
+ string result = JsonConvert.SerializeObject(testDates, new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat });
Assert.AreEqual(@"[""\/Date(-59011455539000+0000)\/"",""\/Date(946688461000+0000)\/"",""\/Date(946641661000+1300)\/"",""\/Date(946701061000-0330)\/""]", result);
}
#endif
@@ -536,7 +551,7 @@ keyword such as type of business.""
};
string json = JsonConvert.SerializeObject(anonymous);
- Assert.AreEqual(@"{""StringValue"":""I am a string"",""IntValue"":2147483647,""NestedAnonymous"":{""NestedValue"":255},""NestedArray"":[1,2],""Product"":{""Name"":""TestProduct"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0,""Sizes"":null}}", json);
+ Assert.AreEqual(@"{""StringValue"":""I am a string"",""IntValue"":2147483647,""NestedAnonymous"":{""NestedValue"":255},""NestedArray"":[1,2],""Product"":{""Name"":""TestProduct"",""ExpiryDate"":""2000-01-01T00:00:00Z"",""Price"":0.0,""Sizes"":null}}", json);
anonymous = JsonConvert.DeserializeAnonymousType(json, anonymous);
Assert.AreEqual("I am a string", anonymous.StringValue);
@@ -565,7 +580,7 @@ keyword such as type of business.""
jsonSerializer.Serialize(sw, collection);
- Assert.AreEqual(@"[{""Name"":""Test1"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0,""Sizes"":null},{""Name"":""Test2"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0,""Sizes"":null},{""Name"":""Test3"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0,""Sizes"":null}]",
+ Assert.AreEqual(@"[{""Name"":""Test1"",""ExpiryDate"":""2000-01-01T00:00:00Z"",""Price"":0.0,""Sizes"":null},{""Name"":""Test2"",""ExpiryDate"":""2000-01-01T00:00:00Z"",""Price"":0.0,""Sizes"":null},{""Name"":""Test3"",""ExpiryDate"":""2000-01-01T00:00:00Z"",""Price"":0.0,""Sizes"":null}]",
sw.GetStringBuilder().ToString());
ProductCollection collectionNew = (ProductCollection) jsonSerializer.Deserialize(new JsonTextReader(new StringReader(sw.GetStringBuilder().ToString())), typeof (ProductCollection));
@@ -819,12 +834,30 @@ keyword such as type of business.""
}
[Test]
- public void SerializerShouldUseMemberConverter()
+ public void SerializerShouldUseMemberConverter_IsoDate()
{
DateTime testDate = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc);
MemberConverterClass m1 = new MemberConverterClass {DefaultConverter = testDate, MemberConverter = testDate};
string json = JsonConvert.SerializeObject(m1);
+ Assert.AreEqual(@"{""DefaultConverter"":""1970-01-01T00:00:00Z"",""MemberConverter"":""1970-01-01T00:00:00Z""}", json);
+
+ MemberConverterClass m2 = JsonConvert.DeserializeObject<MemberConverterClass>(json);
+
+ Assert.AreEqual(testDate, m2.DefaultConverter);
+ Assert.AreEqual(testDate, m2.MemberConverter);
+ }
+
+ [Test]
+ public void SerializerShouldUseMemberConverter_MsDate()
+ {
+ DateTime testDate = new DateTime(JsonConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc);
+ MemberConverterClass m1 = new MemberConverterClass { DefaultConverter = testDate, MemberConverter = testDate };
+
+ string json = JsonConvert.SerializeObject(m1, new JsonSerializerSettings
+ {
+ DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
+ });
Assert.AreEqual(@"{""DefaultConverter"":""\/Date(0)\/"",""MemberConverter"":""1970-01-01T00:00:00Z""}", json);
MemberConverterClass m2 = JsonConvert.DeserializeObject<MemberConverterClass>(json);
@@ -1017,7 +1050,7 @@ keyword such as type of business.""
""FirstName"": ""Bob"",
""MiddleName"": ""Cosmo"",
""LastName"": ""Smith"",
- ""BirthDate"": ""\/Date(977309755000)\/""
+ ""BirthDate"": ""2000-12-20T10:55:55Z""
}", json);
RequiredMembersClass c2 = JsonConvert.DeserializeObject<RequiredMembersClass>(json);
@@ -1775,13 +1808,13 @@ keyword such as type of business.""
Assert.AreEqual(@"[
{
""Name"": ""Product 1"",
- ""ExpiryDate"": ""\/Date(978048000000)\/"",
+ ""ExpiryDate"": ""2000-12-29T00:00:00Z"",
""Price"": 99.95,
""Sizes"": null
},
{
""Name"": ""Product 2"",
- ""ExpiryDate"": ""\/Date(1248998400000)\/"",
+ ""ExpiryDate"": ""2009-07-31T00:00:00Z"",
""Price"": 12.50,
""Sizes"": null
}
@@ -2164,8 +2197,8 @@ keyword such as type of business.""
""Person"": {
""HourlyWage"": 12.50,
""Name"": ""Jim Bob"",
- ""BirthDate"": ""\/Date(975542399000)\/"",
- ""LastModified"": ""\/Date(975542399000)\/""
+ ""BirthDate"": ""2000-11-29T23:59:59Z"",
+ ""LastModified"": ""2000-11-29T23:59:59Z""
}
}",
json);
@@ -2667,7 +2700,7 @@ keyword such as type of business.""
}
[Test]
- public void SerializeISerializableTestObject()
+ public void SerializeISerializableTestObject_IsoDate()
{
Person person = new Person();
person.BirthDate = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc);
@@ -2678,7 +2711,7 @@ keyword such as type of business.""
DateTimeOffset dateTimeOffset = new DateTimeOffset(2000, 12, 20, 22, 59, 59, TimeSpan.FromHours(2));
string dateTimeOffsetText;
#if !NET20
- dateTimeOffsetText = @"\/Date(977345999000+0200)\/";
+ dateTimeOffsetText = @"2000-12-20T22:59:59+02:00";
#else
dateTimeOffsetText = @"12/20/2000 22:59:59 +02:00";
#endif
@@ -2692,6 +2725,63 @@ keyword such as type of business.""
""dateTimeOffsetValue"": """ + dateTimeOffsetText + @""",
""personValue"": {
""Name"": ""Name!"",
+ ""BirthDate"": ""2000-01-01T01:01:01Z"",
+ ""LastModified"": ""2000-01-01T01:01:01Z""
+ },
+ ""nullPersonValue"": null,
+ ""nullableInt"": null,
+ ""booleanValue"": false,
+ ""byteValue"": 0,
+ ""charValue"": ""\u0000"",
+ ""dateTimeValue"": ""0001-01-01T00:00:00Z"",
+ ""decimalValue"": 0.0,
+ ""shortValue"": 0,
+ ""longValue"": 0,
+ ""sbyteValue"": 0,
+ ""floatValue"": 0.0,
+ ""ushortValue"": 0,
+ ""uintValue"": 0,
+ ""ulongValue"": 0
+}", json);
+
+ ISerializableTestObject o2 = JsonConvert.DeserializeObject<ISerializableTestObject>(json);
+ Assert.AreEqual("String!", o2._stringValue);
+ Assert.AreEqual(int.MinValue, o2._intValue);
+ Assert.AreEqual(dateTimeOffset, o2._dateTimeOffsetValue);
+ Assert.AreEqual("Name!", o2._personValue.Name);
+ Assert.AreEqual(null, o2._nullPersonValue);
+ Assert.AreEqual(null, o2._nullableInt);
+ }
+
+ [Test]
+ public void SerializeISerializableTestObject_MsAjax()
+ {
+ Person person = new Person();
+ person.BirthDate = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc);
+ person.LastModified = person.BirthDate;
+ person.Department = "Department!";
+ person.Name = "Name!";
+
+ DateTimeOffset dateTimeOffset = new DateTimeOffset(2000, 12, 20, 22, 59, 59, TimeSpan.FromHours(2));
+ string dateTimeOffsetText;
+#if !NET20
+ dateTimeOffsetText = @"\/Date(977345999000+0200)\/";
+#else
+ dateTimeOffsetText = @"12/20/2000 22:59:59 +02:00";
+#endif
+
+ ISerializableTestObject o = new ISerializableTestObject("String!", int.MinValue, dateTimeOffset, person);
+
+ string json = JsonConvert.SerializeObject(o, Formatting.Indented, new JsonSerializerSettings
+ {
+ DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
+ });
+ Assert.AreEqual(@"{
+ ""stringValue"": ""String!"",
+ ""intValue"": -2147483648,
+ ""dateTimeOffsetValue"": """ + dateTimeOffsetText + @""",
+ ""personValue"": {
+ ""Name"": ""Name!"",
""BirthDate"": ""\/Date(946688461000)\/"",
""LastModified"": ""\/Date(946688461000)\/""
},
@@ -3161,8 +3251,8 @@ keyword such as type of business.""
""Value"": {
""HourlyWage"": 1.0,
""Name"": null,
- ""BirthDate"": ""\/Date(975711661000)\/"",
- ""LastModified"": ""\/Date(975711661000)\/""
+ ""BirthDate"": ""2000-12-01T23:01:01Z"",
+ ""LastModified"": ""2000-12-01T23:01:01Z""
}
},
{
@@ -3170,8 +3260,8 @@ keyword such as type of business.""
""Value"": {
""HourlyWage"": 2.0,
""Name"": null,
- ""BirthDate"": ""\/Date(975711661000)\/"",
- ""LastModified"": ""\/Date(975711661000)\/""
+ ""BirthDate"": ""2000-12-01T23:01:01Z"",
+ ""LastModified"": ""2000-12-01T23:01:01Z""
}
}
]", json);
@@ -3777,13 +3867,34 @@ keyword such as type of business.""
#if !NET20
[Test]
- public void ReadWriteTimeZoneOffset()
+ public void ReadWriteTimeZoneOffsetIso()
{
var serializeObject = JsonConvert.SerializeObject(new TimeZoneOffsetObject
{
Offset = new DateTimeOffset(new DateTime(2000, 1, 1), TimeSpan.FromHours(6))
});
+ Assert.AreEqual("{\"Offset\":\"2000-01-01T00:00:00+06:00\"}", serializeObject);
+ var deserializeObject = JsonConvert.DeserializeObject<TimeZoneOffsetObject>(serializeObject);
+ Assert.AreEqual(TimeSpan.FromHours(6), deserializeObject.Offset.Offset);
+ Assert.AreEqual(new DateTime(2000, 1, 1), deserializeObject.Offset.Date);
+ }
+
+ [Test]
+ public void DeserializePropertyNullableDateTimeOffsetExactIso()
+ {
+ NullableDateTimeTestClass d = JsonConvert.DeserializeObject<NullableDateTimeTestClass>("{\"DateTimeOffsetField\":\"2000-01-01T00:00:00+06:00\"}");
+ Assert.AreEqual(new DateTimeOffset(new DateTime(2000, 1, 1), TimeSpan.FromHours(6)), d.DateTimeOffsetField);
+ }
+
+ [Test]
+ public void ReadWriteTimeZoneOffsetMsAjax()
+ {
+ var serializeObject = JsonConvert.SerializeObject(new TimeZoneOffsetObject
+ {
+ Offset = new DateTimeOffset(new DateTime(2000, 1, 1), TimeSpan.FromHours(6))
+ }, Formatting.None, new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat });
+
Assert.AreEqual("{\"Offset\":\"\\/Date(946663200000+0600)\\/\"}", serializeObject);
var deserializeObject = JsonConvert.DeserializeObject<TimeZoneOffsetObject>(serializeObject);
Assert.AreEqual(TimeSpan.FromHours(6), deserializeObject.Offset.Offset);
@@ -3791,7 +3902,7 @@ keyword such as type of business.""
}
[Test]
- public void DeserializePropertyNullableDateTimeOffsetExact()
+ public void DeserializePropertyNullableDateTimeOffsetExactMsAjax()
{
NullableDateTimeTestClass d = JsonConvert.DeserializeObject<NullableDateTimeTestClass>("{\"DateTimeOffsetField\":\"\\/Date(946663200000+0600)\\/\"}");
Assert.AreEqual(new DateTimeOffset(new DateTime(2000, 1, 1), TimeSpan.FromHours(6)), d.DateTimeOffsetField);
@@ -3839,7 +3950,7 @@ keyword such as type of business.""
""Decimal"": 99.9,
""Complex"": {
""String"": ""I am a string"",
- ""DateTime"": ""\/Date(977338500000)\/""
+ ""DateTime"": ""2000-12-20T18:55:00Z""
}
}", json);
@@ -5168,7 +5279,7 @@ keyword such as type of business.""
}
[Test]
- [ExpectedException(typeof (JsonReaderException), ExpectedMessage = "Unexpected token when reading integer: Boolean. Line 2, position 22.")]
+ [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading integer. Unexpected token: Boolean. Line 2, position 22.")]
public void DeserializeBoolInt()
{
string json = @"{
@@ -5223,7 +5334,7 @@ keyword such as type of business.""
""BrokerID"": ""951663c4-924e-4c86-a57a-7ed737501dbd"",
""Latitude"": 33.657145,
""Longitude"": -117.766684,
- ""TimeStamp"": ""\/Date(951955199000)\/"",
+ ""TimeStamp"": ""2000-03-01T23:59:59Z"",
""Payload"": {
""$type"": ""System.Byte[], mscorlib"",
""$value"": ""AAECAwQFBgcICQ==""
@@ -5372,6 +5483,79 @@ Parameter name: value")]
{
JsonConvert.DeserializeObject(null);
}
+
+ [Test]
+ public void DeserializeIsoDatesWithIsoConverter()
+ {
+ string jsonIsoText =
+ @"{""Value"":""2012-02-25T19:55:50.6095676+13:00""}";
+
+ DateTimeWrapper c = JsonConvert.DeserializeObject<DateTimeWrapper>(jsonIsoText, new IsoDateTimeConverter());
+ Assert.AreEqual(DateTimeKind.Local, c.Value.Kind);
+ }
+
+#if !NET20
+ [Test]
+ public void DeserializeUTC()
+ {
+ DateTimeTestClass c =
+ JsonConvert.DeserializeObject<DateTimeTestClass>(
+ @"{""PreField"":""Pre"",""DateTimeField"":""2008-12-12T12:12:12Z"",""DateTimeOffsetField"":""2008-12-12T12:12:12Z"",""PostField"":""Post""}",
+ new JsonSerializerSettings
+ {
+ DateTimeZoneHandling = DateTimeZoneHandling.Local
+ });
+
+ Assert.AreEqual(new DateTime(2008, 12, 12, 12, 12, 12, 0, DateTimeKind.Utc).ToLocalTime(), c.DateTimeField);
+ Assert.AreEqual(new DateTimeOffset(2008, 12, 12, 12, 12, 12, 0, TimeSpan.Zero), c.DateTimeOffsetField);
+ Assert.AreEqual("Pre", c.PreField);
+ Assert.AreEqual("Post", c.PostField);
+
+ DateTimeTestClass c2 =
+ JsonConvert.DeserializeObject<DateTimeTestClass>(
+ @"{""PreField"":""Pre"",""DateTimeField"":""2008-01-01T01:01:01Z"",""DateTimeOffsetField"":""2008-01-01T01:01:01Z"",""PostField"":""Post""}",
+ new JsonSerializerSettings
+ {
+ DateTimeZoneHandling = DateTimeZoneHandling.Local
+ });
+
+ Assert.AreEqual(new DateTime(2008, 1, 1, 1, 1, 1, 0, DateTimeKind.Utc).ToLocalTime(), c2.DateTimeField);
+ Assert.AreEqual(new DateTimeOffset(2008, 1, 1, 1, 1, 1, 0, TimeSpan.Zero), c2.DateTimeOffsetField);
+ Assert.AreEqual("Pre", c2.PreField);
+ Assert.AreEqual("Post", c2.PostField);
+ }
+
+ [Test]
+ public void NullableDeserializeUTC()
+ {
+ NullableDateTimeTestClass c =
+ JsonConvert.DeserializeObject<NullableDateTimeTestClass>(
+ @"{""PreField"":""Pre"",""DateTimeField"":""2008-12-12T12:12:12Z"",""DateTimeOffsetField"":""2008-12-12T12:12:12Z"",""PostField"":""Post""}",
+ new JsonSerializerSettings
+ {
+ DateTimeZoneHandling = DateTimeZoneHandling.Local
+ });
+
+ Assert.AreEqual(new DateTime(2008, 12, 12, 12, 12, 12, 0, DateTimeKind.Utc).ToLocalTime(), c.DateTimeField);
+ Assert.AreEqual(new DateTimeOffset(2008, 12, 12, 12, 12, 12, 0, TimeSpan.Zero), c.DateTimeOffsetField);
+ Assert.AreEqual("Pre", c.PreField);
+ Assert.AreEqual("Post", c.PostField);
+
+ NullableDateTimeTestClass c2 =
+ JsonConvert.DeserializeObject<NullableDateTimeTestClass>(
+ @"{""PreField"":""Pre"",""DateTimeField"":null,""DateTimeOffsetField"":null,""PostField"":""Post""}");
+
+ Assert.AreEqual(null, c2.DateTimeField);
+ Assert.AreEqual(null, c2.DateTimeOffsetField);
+ Assert.AreEqual("Pre", c2.PreField);
+ Assert.AreEqual("Post", c2.PostField);
+ }
+#endif
+ }
+
+ public class DateTimeWrapper
+ {
+ public DateTime Value { get; set; }
}
public class Widget1
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs
index 2c87e71..21ed6a5 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/NullValueHandlingTests.cs
@@ -62,7 +62,7 @@ namespace Newtonsoft.Json.Tests.Serialization
//JsonConvert.ConvertDateTimeToJavaScriptTicks(s1.Establised.DateTime)
- Assert.AreEqual(@"{""Color"":4,""Establised"":""\/Date(1264122061000)\/"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""\/Date(949532490000)\/"",""Price"":0.0},{""Name"":""Alien"",""ExpiryDate"":""\/Date(946684800000)\/"",""Price"":0.0}]}", sw.GetStringBuilder().ToString());
+ Assert.AreEqual(@"{""Color"":4,""Establised"":""2010-01-22T01:01:01Z"",""Width"":1.1,""Employees"":999,""RoomsPerFloor"":[1,2,3,4,5,6,7,8,9],""Open"":false,""Symbol"":""@"",""Mottos"":[""Hello World"",""öäüÖÄÜ\\'{new Date(12345);}[222]_µ@²³~"",null,"" ""],""Cost"":100980.1,""Escape"":""\r\n\t\f\b?{\\r\\n\""'"",""product"":[{""Name"":""Rocket"",""ExpiryDate"":""2000-02-02T23:01:30Z"",""Price"":0.0},{""Name"":""Alien"",""ExpiryDate"":""2000-01-01T00:00:00Z"",""Price"":0.0}]}", sw.GetStringBuilder().ToString());
Store s2 = (Store)jsonSerializer.Deserialize(new JsonTextReader(new StringReader("{}")), typeof(Store));
Assert.AreEqual("\r\n\t\f\b?{\\r\\n\"\'", s2.Escape);
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs
index a6a4ec5..6532f96 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs
@@ -290,10 +290,10 @@ namespace Newtonsoft.Json.Tests.Serialization
e = ex;
}
- Assert.AreEqual(@"Error converting value ""kjhkjhkjhkjh"" to type 'System.DateTime'. Line 1, position 16.", e.Message);
+ Assert.AreEqual(@"Could not convert string to DateTime: kjhkjhkjhkjh. Line 1, position 16.", e.Message);
Assert.AreEqual(1, errors.Count);
- Assert.AreEqual(@"[0][0] - 0 - Error converting value ""kjhkjhkjhkjh"" to type 'System.DateTime'. Line 1, position 16.", errors[0]);
+ Assert.AreEqual(@"[0][0] - 0 - Could not convert string to DateTime: kjhkjhkjhkjh. Line 1, position 16.", errors[0]);
}
[Test]
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs
index 9d52d82..48af72c 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs
@@ -192,8 +192,8 @@ namespace Newtonsoft.Json.Tests.Serialization
{
""$type"": """ + personRef + @""",
""Name"": null,
- ""BirthDate"": ""\/Date(978134400000)\/"",
- ""LastModified"": ""\/Date(978134400000)\/""
+ ""BirthDate"": ""2000-12-30T00:00:00Z"",
+ ""LastModified"": ""2000-12-30T00:00:00Z""
},
""String!"",
-2147483648
@@ -870,7 +870,7 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual(output, @"{
""$type"": """ + carClassRef + @""",
- ""Year"": ""\/Date(970707661000)\/"",
+ ""Year"": ""2000-10-05T01:01:01Z"",
""Objects"": {
""$type"": ""System.Object[], mscorlib"",
""$values"": [
diff --git a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs
index 7560f02..0a47016 100644
--- a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs
+++ b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs
@@ -26,10 +26,12 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using NUnit.Framework;
+using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Tests
{
@@ -53,5 +55,14 @@ namespace Newtonsoft.Json.Tests
{
return @"@""" + json.Replace(@"""", @"""""") + @"""";
}
+
+ protected string GetOffset(DateTime d, DateFormatHandling dateFormatHandling)
+ {
+ StringWriter sw = new StringWriter();
+ JsonConvert.WriteDateTimeOffset(sw, DateTime.SpecifyKind(d, DateTimeKind.Local).GetUtcOffset(), dateFormatHandling);
+ sw.Flush();
+
+ return sw.ToString();
+ }
}
}
diff --git a/Src/Newtonsoft.Json/Bson/BsonReader.cs b/Src/Newtonsoft.Json/Bson/BsonReader.cs
index c80491d..099e561 100644
--- a/Src/Newtonsoft.Json/Bson/BsonReader.cs
+++ b/Src/Newtonsoft.Json/Bson/BsonReader.cs
@@ -180,49 +180,7 @@ namespace Newtonsoft.Json.Bson
/// </returns>
public override byte[] ReadAsBytes()
{
- Read();
-
- if (IsWrappedInTypeObject())
- {
- byte[] data = ReadAsBytes();
- Read();
- SetToken(JsonToken.Bytes, data);
- return data;
- }
-
- if (TokenType == JsonToken.Null)
- return null;
- if (TokenType == JsonToken.Bytes)
- return (byte[])Value;
-
- if (TokenType == JsonToken.EndArray)
- return null;
-
- throw CreateReaderException(this, "Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
- }
-
- private bool IsWrappedInTypeObject()
- {
- if (TokenType == JsonToken.StartObject)
- {
- Read();
- if (Value.ToString() == "$type")
- {
- Read();
- if (Value != null && Value.ToString().StartsWith("System.Byte[]"))
- {
- Read();
- if (Value.ToString() == "$value")
- {
- return true;
- }
- }
- }
-
- throw CreateReaderException(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
- }
-
- return false;
+ return ReadAsBytesInternal();
}
/// <summary>
@@ -231,35 +189,7 @@ namespace Newtonsoft.Json.Bson
/// <returns>A <see cref="Nullable{Decimal}"/>. This method will return <c>null</c> at the end of an array.</returns>
public override decimal? ReadAsDecimal()
{
- Read();
-
- if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float)
- {
- SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture));
- return (decimal)Value;
- }
-
- if (TokenType == JsonToken.Null)
- return null;
-
- decimal d;
- if (TokenType == JsonToken.String)
- {
- if (decimal.TryParse((string)Value, NumberStyles.Number, Culture, out d))
- {
- SetToken(JsonToken.Float, d);
- return d;
- }
- else
- {
- throw CreateReaderException(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
- }
- }
-
- if (TokenType == JsonToken.EndArray)
- return null;
-
- throw CreateReaderException(this, "Error reading decimal. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ return ReadAsDecimalInternal();
}
/// <summary>
@@ -268,35 +198,25 @@ namespace Newtonsoft.Json.Bson
/// <returns>A <see cref="Nullable{Int32}"/>. This method will return <c>null</c> at the end of an array.</returns>
public override int? ReadAsInt32()
{
- Read();
-
- if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float)
- {
- SetToken(JsonToken.Float, Convert.ToInt32(Value, CultureInfo.InvariantCulture));
- return (int)Value;
- }
-
- if (TokenType == JsonToken.Null)
- return null;
-
- int i;
- if (TokenType == JsonToken.String)
- {
- if (int.TryParse((string)Value, NumberStyles.Integer, Culture, out i))
- {
- SetToken(JsonToken.Integer, i);
- return i;
- }
- else
- {
- throw CreateReaderException(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
- }
- }
+ return ReadAsInt32Internal();
+ }
- if (TokenType == JsonToken.EndArray)
- return null;
+ /// <summary>
+ /// Reads the next JSON token from the stream as a <see cref="String"/>.
+ /// </summary>
+ /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
+ public override string ReadAsString()
+ {
+ return ReadAsStringInternal();
+ }
- throw CreateReaderException(this, "Error reading integer. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ /// <summary>
+ /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTime}"/>.
+ /// </summary>
+ /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
+ public override DateTime? ReadAsDateTime()
+ {
+ return ReadAsDateTimeInternal();
}
#if !NET20
@@ -308,35 +228,7 @@ namespace Newtonsoft.Json.Bson
/// </returns>
public override DateTimeOffset? ReadAsDateTimeOffset()
{
- Read();
-
- if (TokenType == JsonToken.Date)
- {
- SetToken(JsonToken.Date, new DateTimeOffset((DateTime) Value));
- return (DateTimeOffset) Value;
- }
-
- if (TokenType == JsonToken.Null)
- return null;
-
- DateTimeOffset dt;
- if (TokenType == JsonToken.String)
- {
- if (DateTimeOffset.TryParse((string)Value, Culture, DateTimeStyles.None, out dt))
- {
- SetToken(JsonToken.Date, dt);
- return dt;
- }
- else
- {
- throw CreateReaderException(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
- }
- }
-
- if (TokenType == JsonToken.EndArray)
- return null;
-
- throw CreateReaderException(this, "Error reading date. Expected date but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ return ReadAsDateTimeOffsetInternal();
}
#endif
@@ -348,6 +240,13 @@ namespace Newtonsoft.Json.Bson
/// </returns>
public override bool Read()
{
+ _readType = Json.ReadType.Read;
+
+ return ReadInternal();
+ }
+
+ internal override bool ReadInternal()
+ {
try
{
bool success;
diff --git a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
index 2a2dac8..04004b1 100644
--- a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
+++ b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
@@ -107,6 +107,16 @@ namespace Newtonsoft.Json.Converters
return null;
}
+ if (reader.TokenType == JsonToken.Date)
+ {
+#if !PocketPC && !NET20
+ if (t == typeof(DateTimeOffset))
+ return new DateTimeOffset((DateTime)reader.Value);
+#endif
+
+ return reader.Value;
+ }
+
if (reader.TokenType != JsonToken.String)
throw new Exception("Unexpected token parsing date. Expected String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
diff --git a/Src/Newtonsoft.Json/Converters/JsonDateTimeSerializationMode.cs b/Src/Newtonsoft.Json/Converters/JsonDateTimeSerializationMode.cs
deleted file mode 100644
index 089b89d..0000000
--- a/Src/Newtonsoft.Json/Converters/JsonDateTimeSerializationMode.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace Newtonsoft.Json.Converters
-{
- /// <summary>
- /// Specifies whether a DateTime object represents a local time, a Coordinated Universal Time (UTC), or is not specified as either local time or UTC.
- /// </summary>
- public enum JsonDateTimeSerializationMode
- {
- /// <summary>
- /// The time represented is local time.
- /// </summary>
- Local,
- /// <summary>
- /// The time represented is UTC.
- /// </summary>
- Utc,
- /// <summary>
- /// The time represented is not specified as either local time or Coordinated Universal Time (UTC).
- /// </summary>
- Unspecified,
- /// <summary>
- /// Preserves the DateTimeKind field of a date when a DateTime object is converted to a string and the string is then converted back to a DateTime object.
- /// </summary>
- RoundtripKind
- }
-} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/DateFormatHandling.cs b/Src/Newtonsoft.Json/DateFormatHandling.cs
new file mode 100644
index 0000000..55902c7
--- /dev/null
+++ b/Src/Newtonsoft.Json/DateFormatHandling.cs
@@ -0,0 +1,8 @@
+namespace Newtonsoft.Json
+{
+ public enum DateFormatHandling
+ {
+ IsoDateFormat,
+ MicrosoftDateFormat
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/DateTimeZoneHandling.cs b/Src/Newtonsoft.Json/DateTimeZoneHandling.cs
new file mode 100644
index 0000000..9900d23
--- /dev/null
+++ b/Src/Newtonsoft.Json/DateTimeZoneHandling.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// Specifies how to treat the time value when converting between string and <see cref="DateTime"/>.
+ /// </summary>
+ public enum DateTimeZoneHandling
+ {
+ /// <summary>
+ /// Treat as local time. If the <see cref="DateTime"/> object represents a Coordinated Universal Time (UTC), it is converted to the local time.
+ /// </summary>
+ Local,
+ /// <summary>
+ /// Treat as a UTC. If the <see cref="DateTime"/> object represents a local time, it is converted to a UTC.
+ /// </summary>
+ Utc,
+ /// <summary>
+ /// Treat as a local time if a <see cref="DateTime"/> is being converted to a string.
+ /// If a string is being converted to <see cref="DateTime"/>, convert to a local time if a time zone is specified.
+ /// </summary>
+ Unspecified,
+ /// <summary>
+ /// Time zone information should be preserved when converting.
+ /// </summary>
+ RoundtripKind
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Formatting.cs b/Src/Newtonsoft.Json/Formatting.cs
new file mode 100644
index 0000000..1c1de0e
--- /dev/null
+++ b/Src/Newtonsoft.Json/Formatting.cs
@@ -0,0 +1,17 @@
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// Specifies formatting options for the <see cref="JsonTextWriter"/>.
+ /// </summary>
+ public enum Formatting
+ {
+ /// <summary>
+ /// No special formatting is applied. This is the default.
+ /// </summary>
+ None,
+ /// <summary>
+ /// Causes child objects to be indented according to the <see cref="JsonTextWriter.Indentation"/> and <see cref="JsonTextWriter.IndentChar"/> settings.
+ /// </summary>
+ Indented
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs
index fc598bb..210db6c 100644
--- a/Src/Newtonsoft.Json/JsonConvert.cs
+++ b/Src/Newtonsoft.Json/JsonConvert.cs
@@ -85,13 +85,48 @@ namespace Newtonsoft.Json
/// <returns>A JSON string representation of the <see cref="DateTime"/>.</returns>
public static string ToString(DateTime value)
{
+ return ToString(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.RoundtripKind);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="DateTime"/> to its JSON string representation using the <see cref="DateFormatHandling"/> specified.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <param name="format">The format the date will be converted to.</param>
+ /// <returns>A JSON string representation of the <see cref="DateTime"/>.</returns>
+ public static string ToString(DateTime value, DateFormatHandling format, DateTimeZoneHandling timeZoneOption)
+ {
+ DateTime updatedDateTime = EnsureDateTime(value, timeZoneOption);
+
using (StringWriter writer = StringUtils.CreateStringWriter(64))
{
- WriteDateTimeString(writer, value, value.GetUtcOffset(), value.Kind);
+ WriteDateTimeString(writer, updatedDateTime, updatedDateTime.GetUtcOffset(), updatedDateTime.Kind, format);
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 !PocketPC && !NET20
/// <summary>
/// Converts the <see cref="DateTimeOffset"/> to its JSON string representation.
@@ -100,44 +135,88 @@ namespace Newtonsoft.Json
/// <returns>A JSON string representation of the <see cref="DateTimeOffset"/>.</returns>
public static string ToString(DateTimeOffset value)
{
+ return ToString(value, DateFormatHandling.IsoDateFormat);
+ }
+
+ /// <summary>
+ /// Converts the <see cref="DateTimeOffset"/> to its JSON string representation using the <see cref="DateFormatHandling"/> specified.
+ /// </summary>
+ /// <param name="value">The value to convert.</param>
+ /// <param name="format">The format the date will be converted to.</param>
+ /// <returns>A JSON string representation of the <see cref="DateTimeOffset"/>.</returns>
+ public static string ToString(DateTimeOffset value, DateFormatHandling format)
+ {
using (StringWriter writer = StringUtils.CreateStringWriter(64))
{
- WriteDateTimeString(writer, value.UtcDateTime, value.Offset, DateTimeKind.Local);
+ WriteDateTimeString(writer, (format == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, format);
return writer.ToString();
}
}
#endif
- internal static void WriteDateTimeString(TextWriter writer, DateTime value)
+ internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format)
{
- WriteDateTimeString(writer, value, value.GetUtcOffset(), value.Kind);
+ WriteDateTimeString(writer, value, value.GetUtcOffset(), value.Kind, format);
}
- internal static void WriteDateTimeString(TextWriter writer, DateTime value, TimeSpan offset, DateTimeKind kind)
+ internal static void WriteDateTimeString(TextWriter writer, DateTime value, TimeSpan offset, DateTimeKind kind, DateFormatHandling format)
{
- long javaScriptTicks = ConvertDateTimeToJavaScriptTicks(value, offset);
+ if (format == DateFormatHandling.MicrosoftDateFormat)
+ {
+ long javaScriptTicks = ConvertDateTimeToJavaScriptTicks(value, offset);
- writer.Write(@"""\/Date(");
- writer.Write(javaScriptTicks);
+ writer.Write(@"""\/Date(");
+ writer.Write(javaScriptTicks);
- switch (kind)
+ 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
{
- case DateTimeKind.Local:
- case DateTimeKind.Unspecified:
- writer.Write((offset.Ticks >= 0L) ? "+" : "-");
-
- int absHours = Math.Abs(offset.Hours);
- if (absHours < 10)
- writer.Write(0);
- writer.Write(absHours);
- int absMinutes = Math.Abs(offset.Minutes);
- if (absMinutes < 10)
- writer.Write(0);
- writer.Write(absMinutes);
- break;
+ writer.Write(@"""");
+ writer.Write(value.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFF", CultureInfo.InvariantCulture));
+
+ switch (kind)
+ {
+ case DateTimeKind.Local:
+ WriteDateTimeOffset(writer, offset, format);
+ break;
+ case DateTimeKind.Utc:
+ writer.Write("Z");
+ break;
+ }
+
+
+ writer.Write(@"""");
}
+ }
+
+ 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);
- writer.Write(@")\/""");
+ 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)
@@ -150,7 +229,9 @@ namespace Newtonsoft.Json
private static long ToUniversalTicks(DateTime dateTime, TimeSpan offset)
{
- if (dateTime.Kind == DateTimeKind.Utc)
+ // 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;
@@ -196,6 +277,38 @@ namespace Newtonsoft.Json
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;
+ }
+
/// <summary>
/// Converts the <see cref="Boolean"/> to its JSON string representation.
/// </summary>
@@ -583,6 +696,20 @@ namespace Newtonsoft.Json
/// Serializes the specified object to a JSON string using a collection of <see cref="JsonConverter"/>.
/// </summary>
/// <param name="value">The object to serialize.</param>
+ /// <param name="settings">The <see cref="JsonSerializerSettings"/> used to serialize the object.
+ /// If this is null, default serialization settings will be is used.</param>
+ /// <returns>
+ /// A JSON string representation of the object.
+ /// </returns>
+ public static string SerializeObject(object value, JsonSerializerSettings settings)
+ {
+ return SerializeObject(value, Formatting.None, settings);
+ }
+
+ /// <summary>
+ /// Serializes the specified object to a JSON string using a collection of <see cref="JsonConverter"/>.
+ /// </summary>
+ /// <param name="value">The object to serialize.</param>
/// <param name="formatting">Indicates how the output is formatted.</param>
/// <param name="settings">The <see cref="JsonSerializerSettings"/> used to serialize the object.
/// If this is null, default serialization settings will be is used.</param>
diff --git a/Src/Newtonsoft.Json/JsonPosition.cs b/Src/Newtonsoft.Json/JsonPosition.cs
new file mode 100644
index 0000000..c1ecfed
--- /dev/null
+++ b/Src/Newtonsoft.Json/JsonPosition.cs
@@ -0,0 +1,70 @@
+using System.Collections.Generic;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ internal enum JsonContainerType
+ {
+ None,
+ Object,
+ Array,
+ Constructor
+ }
+
+ internal struct JsonPosition
+ {
+ internal JsonContainerType Type;
+ internal int? Position;
+ internal string PropertyName;
+
+ internal void WriteTo(StringBuilder sb)
+ {
+ switch (Type)
+ {
+ case JsonContainerType.Object:
+ if (PropertyName != null)
+ {
+ if (sb.Length > 0)
+ sb.Append(".");
+ sb.Append(PropertyName);
+ }
+ break;
+ case JsonContainerType.Array:
+ case JsonContainerType.Constructor:
+ if (Position != null)
+ {
+ sb.Append("[");
+ sb.Append(Position);
+ sb.Append("]");
+ }
+ break;
+ }
+ }
+
+ internal bool InsideContainer()
+ {
+ switch (Type)
+ {
+ case JsonContainerType.Object:
+ return (PropertyName != null);
+ case JsonContainerType.Array:
+ case JsonContainerType.Constructor:
+ return (Position != null);
+ }
+
+ return false;
+ }
+
+ internal static string BuildPath(IEnumerable<JsonPosition> positions)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ foreach (JsonPosition state in positions)
+ {
+ state.WriteTo(sb);
+ }
+
+ return sb.ToString();
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs
index 691ac82..d982bd7 100644
--- a/Src/Newtonsoft.Json/JsonReader.cs
+++ b/Src/Newtonsoft.Json/JsonReader.cs
@@ -28,77 +28,11 @@ using System.Collections.Generic;
using System.IO;
using System.Globalization;
using System.Linq;
-using System.Text;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json
{
- internal enum JsonContainerType
- {
- None,
- Object,
- Array,
- Constructor
- }
-
- internal struct JsonPosition
- {
- internal JsonContainerType Type;
- internal int? Position;
- internal string PropertyName;
-
- internal void WriteTo(StringBuilder sb)
- {
- switch (Type)
- {
- case JsonContainerType.Object:
- if (PropertyName != null)
- {
- if (sb.Length > 0)
- sb.Append(".");
- sb.Append(PropertyName);
- }
- break;
- case JsonContainerType.Array:
- case JsonContainerType.Constructor:
- if (Position != null)
- {
- sb.Append("[");
- sb.Append(Position);
- sb.Append("]");
- }
- break;
- }
- }
-
- internal bool InsideContainer()
- {
- switch (Type)
- {
- case JsonContainerType.Object:
- return (PropertyName != null);
- case JsonContainerType.Array:
- case JsonContainerType.Constructor:
- return (Position != null);
- }
-
- return false;
- }
-
- internal static string BuildPath(IEnumerable<JsonPosition> positions)
- {
- StringBuilder sb = new StringBuilder();
-
- foreach (JsonPosition state in positions)
- {
- state.WriteTo(sb);
- }
-
- return sb.ToString();
- }
- }
-
/// <summary>
/// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data.
/// </summary>
@@ -168,8 +102,10 @@ namespace Newtonsoft.Json
private object _value;
private char _quoteChar;
internal State _currentState;
+ internal ReadType _readType;
private JsonPosition _currentPosition;
private CultureInfo _culture;
+ private DateTimeZoneHandling _dateTimeZoneHandling;
/// <summary>
/// Gets the current reader state.
@@ -201,6 +137,12 @@ namespace Newtonsoft.Json
protected internal set { _quoteChar = value; }
}
+ public DateTimeZoneHandling DateTimeZoneHandling
+ {
+ get { return _dateTimeZoneHandling; }
+ set { _dateTimeZoneHandling = value; }
+ }
+
/// <summary>
/// Gets the type of the current JSON token.
/// </summary>
@@ -271,6 +213,7 @@ namespace Newtonsoft.Json
{
_currentState = State.Start;
_stack = new List<JsonPosition>(4);
+ _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
CloseInput = true;
}
@@ -330,6 +273,12 @@ namespace Newtonsoft.Json
public abstract int? ReadAsInt32();
/// <summary>
+ /// Reads the next JSON token from the stream as a <see cref="String"/>.
+ /// </summary>
+ /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
+ public abstract string ReadAsString();
+
+ /// <summary>
/// Reads the next JSON token from the stream as a <see cref="T:Byte[]"/>.
/// </summary>
/// <returns>A <see cref="T:Byte[]"/> or a null reference if the next JSON token is null. This method will return <c>null</c> at the end of an array.</returns>
@@ -341,6 +290,12 @@ namespace Newtonsoft.Json
/// <returns>A <see cref="Nullable{Decimal}"/>. This method will return <c>null</c> at the end of an array.</returns>
public abstract decimal? ReadAsDecimal();
+ /// <summary>
+ /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTime}"/>.
+ /// </summary>
+ /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
+ public abstract DateTime? ReadAsDateTime();
+
#if !NET20
/// <summary>
/// Reads the next JSON token from the stream as a <see cref="Nullable{DateTimeOffset}"/>.
@@ -349,6 +304,329 @@ namespace Newtonsoft.Json
public abstract DateTimeOffset? ReadAsDateTimeOffset();
#endif
+ internal virtual bool ReadInternal()
+ {
+ throw new NotImplementedException();
+ }
+
+#if !NET20
+ internal DateTimeOffset? ReadAsDateTimeOffsetInternal()
+ {
+ _readType = ReadType.ReadAsDateTimeOffset;
+
+ do
+ {
+ if (!ReadInternal())
+ {
+ SetToken(JsonToken.None);
+ return null;
+ }
+ } while (TokenType == JsonToken.Comment);
+
+ if (TokenType == JsonToken.Date)
+ {
+ if (Value is DateTime)
+ SetToken(JsonToken.Date, new DateTimeOffset((DateTime)Value));
+
+ return (DateTimeOffset)Value;
+ }
+
+ if (TokenType == JsonToken.Null)
+ return null;
+
+ DateTimeOffset dt;
+ if (TokenType == JsonToken.String)
+ {
+ if (DateTimeOffset.TryParse((string)Value, Culture, DateTimeStyles.RoundtripKind, out dt))
+ {
+ SetToken(JsonToken.Date, dt);
+ return dt;
+ }
+ else
+ {
+ throw CreateReaderException(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
+ }
+ }
+
+ if (TokenType == JsonToken.EndArray)
+ return null;
+
+ throw CreateReaderException(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+#endif
+
+ internal byte[] ReadAsBytesInternal()
+ {
+ _readType = ReadType.ReadAsBytes;
+
+ do
+ {
+ if (!ReadInternal())
+ {
+ SetToken(JsonToken.None);
+ return null;
+ }
+ } while (TokenType == JsonToken.Comment);
+
+ if (IsWrappedInTypeObject())
+ {
+ byte[] data = ReadAsBytes();
+ ReadInternal();
+ SetToken(JsonToken.Bytes, data);
+ return data;
+ }
+
+ // attempt to convert possible base 64 string to bytes
+ if (TokenType == JsonToken.String)
+ {
+ string s = (string)Value;
+ byte[] data = (s.Length == 0) ? new byte[0] : Convert.FromBase64String(s);
+ SetToken(JsonToken.Bytes, data);
+ }
+
+ if (TokenType == JsonToken.Null)
+ return null;
+
+ if (TokenType == JsonToken.Bytes)
+ return (byte[])Value;
+
+ if (TokenType == JsonToken.StartArray)
+ {
+ List<byte> data = new List<byte>();
+
+ while (ReadInternal())
+ {
+ switch (TokenType)
+ {
+ case JsonToken.Integer:
+ data.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture));
+ break;
+ case JsonToken.EndArray:
+ byte[] d = data.ToArray();
+ SetToken(JsonToken.Bytes, d);
+ return d;
+ case JsonToken.Comment:
+ // skip
+ break;
+ default:
+ throw CreateReaderException(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+ }
+
+ throw CreateReaderException(this, "Unexpected end when reading bytes.");
+ }
+
+ if (TokenType == JsonToken.EndArray)
+ return null;
+
+ throw CreateReaderException(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+
+ internal decimal? ReadAsDecimalInternal()
+ {
+ _readType = ReadType.ReadAsDecimal;
+
+ do
+ {
+ if (!ReadInternal())
+ {
+ SetToken(JsonToken.None);
+ return null;
+ }
+ } while (TokenType == JsonToken.Comment);
+
+ if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float)
+ {
+ if (!(Value is decimal))
+ SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture));
+
+ return (decimal)Value;
+ }
+
+ if (TokenType == JsonToken.Null)
+ return null;
+
+ decimal d;
+ if (TokenType == JsonToken.String)
+ {
+ if (decimal.TryParse((string)Value, NumberStyles.Number, Culture, out d))
+ {
+ SetToken(JsonToken.Float, d);
+ return d;
+ }
+ else
+ {
+ throw CreateReaderException(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
+ }
+ }
+
+ if (TokenType == JsonToken.EndArray)
+ return null;
+
+ throw CreateReaderException(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+
+ internal int? ReadAsInt32Internal()
+ {
+ _readType = ReadType.ReadAsInt32;
+
+ do
+ {
+ if (!ReadInternal())
+ {
+ SetToken(JsonToken.None);
+ return null;
+ }
+ } while (TokenType == JsonToken.Comment);
+
+ if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float)
+ {
+ if (!(Value is int))
+ SetToken(JsonToken.Integer, Convert.ToInt32(Value, CultureInfo.InvariantCulture));
+
+ return (int)Value;
+ }
+
+ if (TokenType == JsonToken.Null)
+ return null;
+
+ int i;
+ if (TokenType == JsonToken.String)
+ {
+ if (int.TryParse((string)Value, NumberStyles.Integer, Culture, out i))
+ {
+ SetToken(JsonToken.Integer, i);
+ return i;
+ }
+ else
+ {
+ throw CreateReaderException(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
+ }
+ }
+
+ if (TokenType == JsonToken.EndArray)
+ return null;
+
+ throw CreateReaderException(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+
+ internal string ReadAsStringInternal()
+ {
+ _readType = ReadType.ReadAsString;
+
+ do
+ {
+ if (!ReadInternal())
+ {
+ SetToken(JsonToken.None);
+ return null;
+ }
+ } while (TokenType == JsonToken.Comment);
+
+ if (TokenType == JsonToken.String)
+ return (string)Value;
+
+ if (TokenType == JsonToken.Null)
+ return null;
+
+ if (IsPrimitiveToken(TokenType))
+ {
+ if (Value != null)
+ {
+ string s;
+ if (Value is IConvertible)
+ s = ((IConvertible)Value).ToString(Culture);
+ else if (Value is IFormattable)
+ s = ((IFormattable)Value).ToString(null, Culture);
+ else
+ s = Value.ToString();
+
+ SetToken(JsonToken.String, s);
+ return s;
+ }
+ }
+
+ if (TokenType == JsonToken.EndArray)
+ return null;
+
+ throw CreateReaderException(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+
+ internal DateTime? ReadAsDateTimeInternal()
+ {
+ _readType = ReadType.ReadAsDateTime;
+
+ do
+ {
+ if (!ReadInternal())
+ {
+ SetToken(JsonToken.None);
+ return null;
+ }
+ } while (TokenType == JsonToken.Comment);
+
+ if (TokenType == JsonToken.Date)
+ return (DateTime)Value;
+
+ if (TokenType == JsonToken.Null)
+ return null;
+
+ DateTime dt;
+ if (TokenType == JsonToken.String)
+ {
+ string s = (string)Value;
+ if (string.IsNullOrEmpty(s))
+ {
+ SetToken(JsonToken.Null);
+ return null;
+ }
+
+ if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
+ {
+ dt = JsonConvert.EnsureDateTime(dt, DateTimeZoneHandling);
+ SetToken(JsonToken.Date, dt);
+ return dt;
+ }
+ else
+ {
+ throw CreateReaderException(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
+ }
+ }
+
+ if (TokenType == JsonToken.EndArray)
+ return null;
+
+ throw CreateReaderException(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ }
+
+ private bool IsWrappedInTypeObject()
+ {
+ _readType = ReadType.Read;
+
+ if (TokenType == JsonToken.StartObject)
+ {
+ if (!ReadInternal())
+ throw CreateReaderException(this, "Unexpected end when reading bytes.");
+
+ if (Value.ToString() == "$type")
+ {
+ ReadInternal();
+ if (Value != null && Value.ToString().StartsWith("System.Byte[]"))
+ {
+ ReadInternal();
+ if (Value.ToString() == "$value")
+ {
+ return true;
+ }
+ }
+ }
+
+ throw CreateReaderException(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
+ }
+
+ return false;
+ }
+
/// <summary>
/// Skips the children of the current token.
/// </summary>
diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs
index fbbc33a..4f01433 100644
--- a/Src/Newtonsoft.Json/JsonSerializer.cs
+++ b/Src/Newtonsoft.Json/JsonSerializer.cs
@@ -25,6 +25,7 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Runtime.Serialization.Formatters;
using Newtonsoft.Json.Converters;
@@ -56,6 +57,10 @@ namespace Newtonsoft.Json
private IReferenceResolver _referenceResolver;
private SerializationBinder _binder;
private StreamingContext _context;
+ private Formatting? _formatting;
+ private DateFormatHandling? _dateFormatHandling;
+ private DateTimeZoneHandling? _dateTimeZoneHandling;
+ private CultureInfo _culture;
/// <summary>
/// Occurs when the <see cref="JsonSerializer"/> errors during serialization and deserialization.
@@ -279,6 +284,30 @@ namespace Newtonsoft.Json
get { return _context; }
set { _context = value; }
}
+
+ public virtual Formatting Formatting
+ {
+ get { return _formatting ?? JsonSerializerSettings.DefaultFormatting; }
+ set { _formatting = value; }
+ }
+
+ public virtual DateFormatHandling DateFormatHandling
+ {
+ get { return _dateFormatHandling ?? JsonSerializerSettings.DefaultDateFormatHandling; }
+ set { _dateFormatHandling = value; }
+ }
+
+ public virtual DateTimeZoneHandling DateTimeZoneHandling
+ {
+ get { return _dateTimeZoneHandling ?? JsonSerializerSettings.DefaultDateTimeZoneHandling; }
+ set { _dateTimeZoneHandling = value; }
+ }
+
+ public virtual CultureInfo Culture
+ {
+ get { return _culture ?? JsonSerializerSettings.DefaultCulture; }
+ set { _culture = value; }
+ }
#endregion
/// <summary>
@@ -295,7 +324,6 @@ namespace Newtonsoft.Json
_constructorHandling = JsonSerializerSettings.DefaultConstructorHandling;
_typeNameHandling = JsonSerializerSettings.DefaultTypeNameHandling;
_context = JsonSerializerSettings.DefaultContext;
-
_binder = DefaultSerializationBinder.Instance;
}
@@ -313,6 +341,7 @@ namespace Newtonsoft.Json
if (!CollectionUtils.IsNullOrEmpty(settings.Converters))
jsonSerializer.Converters.AddRange(settings.Converters);
+ // serializer specific
jsonSerializer.TypeNameHandling = settings.TypeNameHandling;
jsonSerializer.TypeNameAssemblyFormat = settings.TypeNameAssemblyFormat;
jsonSerializer.PreserveReferencesHandling = settings.PreserveReferencesHandling;
@@ -324,6 +353,13 @@ namespace Newtonsoft.Json
jsonSerializer.ConstructorHandling = settings.ConstructorHandling;
jsonSerializer.Context = settings.Context;
+ // reader specific
+ // unset values won't override reader set values
+ jsonSerializer._formatting = settings._formatting;
+ jsonSerializer._dateFormatHandling = settings._dateFormatHandling;
+ jsonSerializer._dateTimeZoneHandling = settings._dateTimeZoneHandling;
+ jsonSerializer._culture = settings._culture;
+
if (settings.Error != null)
jsonSerializer.Error += settings.Error;
@@ -417,8 +453,30 @@ namespace Newtonsoft.Json
{
ValidationUtils.ArgumentNotNull(reader, "reader");
+ // set serialization options onto reader
+ CultureInfo previousCulture = null;
+ if (_culture != null && reader.Culture != _culture)
+ {
+ previousCulture = reader.Culture;
+ reader.Culture = _culture;
+ }
+ DateTimeZoneHandling? previousDateTimeZoneHandling = null;
+ if (_dateTimeZoneHandling != null && reader.DateTimeZoneHandling != _dateTimeZoneHandling)
+ {
+ previousDateTimeZoneHandling = reader.DateTimeZoneHandling;
+ reader.DateTimeZoneHandling = _dateTimeZoneHandling.Value;
+ }
+
JsonSerializerInternalReader serializerReader = new JsonSerializerInternalReader(this);
- return serializerReader.Deserialize(reader, objectType);
+ object value = serializerReader.Deserialize(reader, objectType);
+
+ // reset reader back to previous options
+ if (previousCulture != null)
+ reader.Culture = previousCulture;
+ if (previousDateTimeZoneHandling != null)
+ reader.DateTimeZoneHandling = previousDateTimeZoneHandling.Value;
+
+ return value;
}
/// <summary>
@@ -447,8 +505,36 @@ namespace Newtonsoft.Json
{
ValidationUtils.ArgumentNotNull(jsonWriter, "jsonWriter");
+ // set serialization options onto writer
+ Formatting? previousFormatting = null;
+ if (_formatting != null && jsonWriter.Formatting != _formatting)
+ {
+ previousFormatting = jsonWriter.Formatting;
+ jsonWriter.Formatting = _formatting.Value;
+ }
+ DateFormatHandling? previousDateFormatHandling = null;
+ if (_dateFormatHandling != null && jsonWriter.DateFormatHandling != _dateFormatHandling)
+ {
+ previousDateFormatHandling = jsonWriter.DateFormatHandling;
+ jsonWriter.DateFormatHandling = _dateFormatHandling.Value;
+ }
+ DateTimeZoneHandling? previousDateTimeZoneHandling = null;
+ if (_dateTimeZoneHandling != null && jsonWriter.DateTimeZoneHandling != _dateTimeZoneHandling)
+ {
+ previousDateTimeZoneHandling = jsonWriter.DateTimeZoneHandling;
+ jsonWriter.DateTimeZoneHandling = _dateTimeZoneHandling.Value;
+ }
+
JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(this);
serializerWriter.Serialize(jsonWriter, value);
+
+ // reset writer back to previous options
+ if (previousFormatting != null)
+ jsonWriter.Formatting = previousFormatting.Value;
+ if (previousDateFormatHandling != null)
+ jsonWriter.DateFormatHandling = previousDateFormatHandling.Value;
+ if (previousDateTimeZoneHandling != null)
+ jsonWriter.DateTimeZoneHandling = previousDateTimeZoneHandling.Value;
}
internal JsonConverter GetMatchingConverter(Type type)
diff --git a/Src/Newtonsoft.Json/JsonSerializerSettings.cs b/Src/Newtonsoft.Json/JsonSerializerSettings.cs
index 1d18e03..7ab24a3 100644
--- a/Src/Newtonsoft.Json/JsonSerializerSettings.cs
+++ b/Src/Newtonsoft.Json/JsonSerializerSettings.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Runtime.Serialization.Formatters;
using System.Text;
@@ -25,6 +26,16 @@ namespace Newtonsoft.Json
internal const FormatterAssemblyStyle DefaultTypeNameAssemblyFormat = FormatterAssemblyStyle.Simple;
internal static readonly StreamingContext DefaultContext;
+ internal const Formatting DefaultFormatting = Formatting.None;
+ internal const DateFormatHandling DefaultDateFormatHandling = DateFormatHandling.IsoDateFormat;
+ internal const DateTimeZoneHandling DefaultDateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
+ internal static readonly CultureInfo DefaultCulture;
+
+ internal Formatting? _formatting;
+ internal DateFormatHandling? _dateFormatHandling;
+ internal DateTimeZoneHandling? _dateTimeZoneHandling;
+ internal CultureInfo _culture;
+
/// <summary>
/// Gets or sets how reference loops (e.g. a class referencing itself) is handled.
/// </summary>
@@ -116,9 +127,34 @@ namespace Newtonsoft.Json
/// <value>The context.</value>
public StreamingContext Context { get; set; }
+ public Formatting Formatting
+ {
+ get { return _formatting ?? DefaultFormatting; }
+ set { _formatting = value; }
+ }
+
+ public DateFormatHandling DateFormatHandling
+ {
+ get { return _dateFormatHandling ?? DefaultDateFormatHandling; }
+ set { _dateFormatHandling = value; }
+ }
+
+ public DateTimeZoneHandling DateTimeZoneHandling
+ {
+ get { return _dateTimeZoneHandling ?? DefaultDateTimeZoneHandling; }
+ set { _dateTimeZoneHandling = value; }
+ }
+
+ public CultureInfo Culture
+ {
+ get { return _culture ?? DefaultCulture; }
+ set { _culture = value; }
+ }
+
static JsonSerializerSettings()
{
DefaultContext = new StreamingContext();
+ DefaultCulture = CultureInfo.InvariantCulture;
}
/// <summary>
@@ -135,6 +171,7 @@ namespace Newtonsoft.Json
TypeNameHandling = DefaultTypeNameHandling;
TypeNameAssemblyFormat = DefaultTypeNameAssemblyFormat;
Context = DefaultContext;
+
Converters = new List<JsonConverter>();
}
}
diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs
index eb792c2..f409175 100644
--- a/Src/Newtonsoft.Json/JsonTextReader.cs
+++ b/Src/Newtonsoft.Json/JsonTextReader.cs
@@ -34,24 +34,24 @@ using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json
{
- /// <summary>
- /// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data.
- /// </summary>
- public class JsonTextReader : JsonReader, IJsonLineInfo
+ internal enum ReadType
{
- private enum ReadType
- {
- Read,
- ReadAsInt32,
- ReadAsBytes,
- ReadAsDecimal,
+ Read,
+ ReadAsInt32,
+ ReadAsBytes,
+ ReadAsString,
+ ReadAsDecimal,
+ ReadAsDateTime,
#if !NET20
- ReadAsDateTimeOffset
+ ReadAsDateTimeOffset
#endif
- }
-
- private ReadType _readType;
+ }
+ /// <summary>
+ /// Represents a reader that provides fast, non-cached, forward-only access to JSON text data.
+ /// </summary>
+ public class JsonTextReader : JsonReader, IJsonLineInfo
+ {
private readonly TextReader _reader;
private char[] _chars;
@@ -124,20 +124,117 @@ namespace Newtonsoft.Json
SetToken(JsonToken.Bytes, data);
}
+ else if (_readType == ReadType.ReadAsString)
+ {
+ string text = _stringReference.ToString();
+
+ SetToken(JsonToken.String, text);
+ QuoteChar = quote;
+ }
else
{
string text = _stringReference.ToString();
- if (text.StartsWith("/Date(", StringComparison.Ordinal) && text.EndsWith(")/", StringComparison.Ordinal))
+ if (text.Length > 0)
{
- ParseDate(text);
+ if (text[0] == '/')
+ {
+ if (text.StartsWith("/Date(", StringComparison.Ordinal) && text.EndsWith(")/", StringComparison.Ordinal))
+ {
+ ParseDateMicrosoft(text);
+ return;
+ }
+ }
+ else if (char.IsDigit(text[0]) && text.Length >= 19 && text.Length <= 40)
+ {
+ if (ParseDateIso(text))
+ return;
+ }
}
- else
+
+ SetToken(JsonToken.String, text);
+ QuoteChar = quote;
+ }
+ }
+
+ private bool ParseDateIso(string text)
+ {
+#if !NET20
+ if (_readType == ReadType.ReadAsDateTimeOffset)
+ {
+ DateTimeOffset dateTimeOffset;
+ if (DateTimeOffset.TryParseExact(text, "yyyy-MM-ddTHH:mm:ss.FFFFFFFK", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateTimeOffset))
{
- SetToken(JsonToken.String, text);
- QuoteChar = quote;
+ SetToken(JsonToken.Date, dateTimeOffset);
+ return true;
}
}
+ else
+#endif
+ {
+ DateTime dateTime;
+ if (DateTime.TryParseExact(text, "yyyy-MM-ddTHH:mm:ss.FFFFFFFK", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateTime))
+ {
+ dateTime = JsonConvert.EnsureDateTime(dateTime, DateTimeZoneHandling);
+
+ SetToken(JsonToken.Date, dateTime);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void ParseDateMicrosoft(string text)
+ {
+ 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 = JsonConvert.ConvertJavaScriptTicksToDateTime(javaScriptTicks);
+
+#if !NET20
+ if (_readType == ReadType.ReadAsDateTimeOffset)
+ {
+ SetToken(JsonToken.Date, new DateTimeOffset(utcDateTime.Add(offset).Ticks, offset));
+ }
+ 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;
+ }
+
+ dateTime = JsonConvert.EnsureDateTime(dateTime, DateTimeZoneHandling);
+
+ SetToken(JsonToken.Date, dateTime);
+ }
}
private static void BlockCopyChars(char[] src, int srcOffset, char[] dst, int dstOffset, int count)
@@ -267,56 +364,6 @@ namespace Newtonsoft.Json
return offset;
}
- private void ParseDate(string text)
- {
- 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 = JsonConvert.ConvertJavaScriptTicksToDateTime(javaScriptTicks);
-
-#if !NET20
- if (_readType == ReadType.ReadAsDateTimeOffset)
- {
- SetToken(JsonToken.Date, new DateTimeOffset(utcDateTime.Add(offset).Ticks, offset));
- }
- 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;
- }
-
- SetToken(JsonToken.Date, dateTime);
- }
- }
-
/// <summary>
/// Reads the next JSON token from the stream.
/// </summary>
@@ -336,34 +383,6 @@ namespace Newtonsoft.Json
return true;
}
- private bool IsWrappedInTypeObject()
- {
- _readType = ReadType.Read;
-
- if (TokenType == JsonToken.StartObject)
- {
- if (!ReadInternal())
- throw CreateReaderException(this, "Unexpected end when reading bytes.");
-
- if (Value.ToString() == "$type")
- {
- ReadInternal();
- if (Value != null && Value.ToString().StartsWith("System.Byte[]"))
- {
- ReadInternal();
- if (Value.ToString() == "$value")
- {
- return true;
- }
- }
- }
-
- throw CreateReaderException(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
- }
-
- return false;
- }
-
/// <summary>
/// Reads the next JSON token from the stream as a <see cref="T:Byte[]"/>.
/// </summary>
@@ -372,61 +391,7 @@ namespace Newtonsoft.Json
/// </returns>
public override byte[] ReadAsBytes()
{
- _readType = ReadType.ReadAsBytes;
-
- do
- {
- if (!ReadInternal())
- {
- SetToken(JsonToken.None);
- return null;
- }
- } while (TokenType == JsonToken.Comment);
-
- if (IsWrappedInTypeObject())
- {
- byte[] data = ReadAsBytes();
- ReadInternal();
- SetToken(JsonToken.Bytes, data);
- return data;
- }
-
- if (TokenType == JsonToken.Null)
- return null;
-
- if (TokenType == JsonToken.Bytes)
- return (byte[])Value;
-
- if (TokenType == JsonToken.StartArray)
- {
- List<byte> data = new List<byte>();
-
- while (ReadInternal())
- {
- switch (TokenType)
- {
- case JsonToken.Integer:
- data.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture));
- break;
- case JsonToken.EndArray:
- byte[] d = data.ToArray();
- SetToken(JsonToken.Bytes, d);
- return d;
- case JsonToken.Comment:
- // skip
- break;
- default:
- throw CreateReaderException(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
- }
- }
-
- throw CreateReaderException(this, "Unexpected end when reading bytes.");
- }
-
- if (TokenType == JsonToken.EndArray)
- return null;
-
- throw CreateReaderException(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ return ReadAsBytesInternal();
}
/// <summary>
@@ -435,41 +400,7 @@ namespace Newtonsoft.Json
/// <returns>A <see cref="Nullable{Decimal}"/>. This method will return <c>null</c> at the end of an array.</returns>
public override decimal? ReadAsDecimal()
{
- _readType = ReadType.ReadAsDecimal;
-
- do
- {
- if (!ReadInternal())
- {
- SetToken(JsonToken.None);
- return null;
- }
- } while (TokenType == JsonToken.Comment);
-
- if (TokenType == JsonToken.Float)
- return (decimal?)Value;
-
- if (TokenType == JsonToken.Null)
- return null;
-
- decimal d;
- if (TokenType == JsonToken.String)
- {
- if (decimal.TryParse((string)Value, NumberStyles.Number, Culture, out d))
- {
- SetToken(JsonToken.Float, d);
- return d;
- }
- else
- {
- throw CreateReaderException(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
- }
- }
-
- if (TokenType == JsonToken.EndArray)
- return null;
-
- throw CreateReaderException(this, "Unexpected token when reading decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ return ReadAsDecimalInternal();
}
/// <summary>
@@ -478,41 +409,25 @@ namespace Newtonsoft.Json
/// <returns>A <see cref="Nullable{Int32}"/>. This method will return <c>null</c> at the end of an array.</returns>
public override int? ReadAsInt32()
{
- _readType = ReadType.ReadAsInt32;
-
- do
- {
- if (!ReadInternal())
- {
- SetToken(JsonToken.None);
- return null;
- }
- } while (TokenType == JsonToken.Comment);
-
- if (TokenType == JsonToken.Integer)
- return (int?)Value;
-
- if (TokenType == JsonToken.Null)
- return null;
-
- int i;
- if (TokenType == JsonToken.String)
- {
- if (int.TryParse((string)Value, NumberStyles.Integer, Culture, out i))
- {
- SetToken(JsonToken.Integer, i);
- return i;
- }
- else
- {
- throw CreateReaderException(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
- }
- }
+ return ReadAsInt32Internal();
+ }
- if (TokenType == JsonToken.EndArray)
- return null;
+ /// <summary>
+ /// Reads the next JSON token from the stream as a <see cref="String"/>.
+ /// </summary>
+ /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
+ public override string ReadAsString()
+ {
+ return ReadAsStringInternal();
+ }
- throw CreateReaderException(this, "Unexpected token when reading integer: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ /// <summary>
+ /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTime}"/>.
+ /// </summary>
+ /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
+ public override DateTime? ReadAsDateTime()
+ {
+ return ReadAsDateTimeInternal();
}
#if !NET20
@@ -522,45 +437,11 @@ namespace Newtonsoft.Json
/// <returns>A <see cref="DateTimeOffset"/>. This method will return <c>null</c> at the end of an array.</returns>
public override DateTimeOffset? ReadAsDateTimeOffset()
{
- _readType = ReadType.ReadAsDateTimeOffset;
-
- do
- {
- if (!ReadInternal())
- {
- SetToken(JsonToken.None);
- return null;
- }
- } while (TokenType == JsonToken.Comment);
-
- if (TokenType == JsonToken.Date)
- return (DateTimeOffset)Value;
-
- if (TokenType == JsonToken.Null)
- return null;
-
- DateTimeOffset dt;
- if (TokenType == JsonToken.String)
- {
- if (DateTimeOffset.TryParse((string)Value, Culture, DateTimeStyles.None, out dt))
- {
- SetToken(JsonToken.Date, dt);
- return dt;
- }
- else
- {
- throw CreateReaderException(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
- }
- }
-
- if (TokenType == JsonToken.EndArray)
- return null;
-
- throw CreateReaderException(this, "Unexpected token when reading date: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ return ReadAsDateTimeOffsetInternal();
}
#endif
- private bool ReadInternal()
+ internal override bool ReadInternal()
{
while (true)
{
diff --git a/Src/Newtonsoft.Json/JsonTextWriter.cs b/Src/Newtonsoft.Json/JsonTextWriter.cs
index 7e3d1dc..1859a21 100644
--- a/Src/Newtonsoft.Json/JsonTextWriter.cs
+++ b/Src/Newtonsoft.Json/JsonTextWriter.cs
@@ -25,6 +25,7 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Text;
using System.IO;
using System.Xml;
@@ -426,8 +427,10 @@ namespace Newtonsoft.Json
/// <param name="value">The <see cref="DateTime"/> value to write.</param>
public override void WriteValue(DateTime value)
{
+
+
base.WriteValue(value);
- JsonConvert.WriteDateTimeString(_writer, value);
+ JsonConvert.WriteDateTimeString(_writer, value, DateFormatHandling);
}
/// <summary>
@@ -455,7 +458,7 @@ namespace Newtonsoft.Json
public override void WriteValue(DateTimeOffset value)
{
base.WriteValue(value);
- WriteValueInternal(JsonConvert.ToString(value), JsonToken.Date);
+ WriteValueInternal(JsonConvert.ToString(value, DateFormatHandling), JsonToken.Date);
}
#endif
diff --git a/Src/Newtonsoft.Json/JsonValidatingReader.cs b/Src/Newtonsoft.Json/JsonValidatingReader.cs
index 15c5ff4..2bf2af6 100644
--- a/Src/Newtonsoft.Json/JsonValidatingReader.cs
+++ b/Src/Newtonsoft.Json/JsonValidatingReader.cs
@@ -390,6 +390,30 @@ namespace Newtonsoft.Json
return d;
}
+ /// <summary>
+ /// Reads the next JSON token from the stream as a <see cref="String"/>.
+ /// </summary>
+ /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
+ public override string ReadAsString()
+ {
+ string s = _reader.ReadAsString();
+
+ ValidateCurrentToken();
+ return s;
+ }
+
+ /// <summary>
+ /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTime}"/>.
+ /// </summary>
+ /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
+ public override DateTime? ReadAsDateTime()
+ {
+ DateTime? dateTime = _reader.ReadAsDateTime();
+
+ ValidateCurrentToken();
+ return dateTime;
+ }
+
#if !NET20
/// <summary>
/// Reads the next JSON token from the stream as a <see cref="Nullable{DateTimeOffset}"/>.
diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs
index a4e9289..9d4e48b 100644
--- a/Src/Newtonsoft.Json/JsonWriter.cs
+++ b/Src/Newtonsoft.Json/JsonWriter.cs
@@ -36,58 +36,6 @@ using System.Globalization;
namespace Newtonsoft.Json
{
/// <summary>
- /// Specifies the state of the <see cref="JsonWriter"/>.
- /// </summary>
- public enum WriteState
- {
- /// <summary>
- /// An exception has been thrown, which has left the <see cref="JsonWriter"/> in an invalid state.
- /// You may call the <see cref="JsonWriter.Close"/> method to put the <see cref="JsonWriter"/> in the <c>Closed</c> state.
- /// Any other <see cref="JsonWriter"/> method calls results in an <see cref="InvalidOperationException"/> being thrown.
- /// </summary>
- Error,
- /// <summary>
- /// The <see cref="JsonWriter.Close"/> method has been called.
- /// </summary>
- Closed,
- /// <summary>
- /// An object is being written.
- /// </summary>
- Object,
- /// <summary>
- /// A array is being written.
- /// </summary>
- Array,
- /// <summary>
- /// A constructor is being written.
- /// </summary>
- Constructor,
- /// <summary>
- /// A property is being written.
- /// </summary>
- Property,
- /// <summary>
- /// A write method has not been called.
- /// </summary>
- Start
- }
-
- /// <summary>
- /// Specifies formatting options for the <see cref="JsonTextWriter"/>.
- /// </summary>
- public enum Formatting
- {
- /// <summary>
- /// No special formatting is applied. This is the default.
- /// </summary>
- None,
- /// <summary>
- /// Causes child objects to be indented according to the <see cref="JsonTextWriter.Indentation"/> and <see cref="JsonTextWriter.IndentChar"/> settings.
- /// </summary>
- Indented
- }
-
- /// <summary>
/// Represents a writer that provides a fast, non-cached, forward-only way of generating Json data.
/// </summary>
public abstract class JsonWriter : IDisposable
@@ -252,6 +200,9 @@ namespace Newtonsoft.Json
}
}
+ private DateFormatHandling _dateFormatHandling;
+ private DateTimeZoneHandling _dateTimeZoneHandling;
+
/// <summary>
/// Indicates how the output is formatted.
/// </summary>
@@ -261,6 +212,18 @@ namespace Newtonsoft.Json
set { _formatting = value; }
}
+ public DateFormatHandling DateFormatHandling
+ {
+ get { return _dateFormatHandling; }
+ set { _dateFormatHandling = value; }
+ }
+
+ public DateTimeZoneHandling DateTimeZoneHandling
+ {
+ get { return _dateTimeZoneHandling; }
+ set { _dateTimeZoneHandling = value; }
+ }
+
/// <summary>
/// Creates an instance of the <c>JsonWriter</c> class.
/// </summary>
@@ -269,6 +232,7 @@ namespace Newtonsoft.Json
_stack = new List<JsonPosition>(4);
_currentState = State.Start;
_formatting = Formatting.None;
+ _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
CloseOutput = true;
}
diff --git a/Src/Newtonsoft.Json/Linq/JTokenReader.cs b/Src/Newtonsoft.Json/Linq/JTokenReader.cs
index 0faf9b4..32c6bf1 100644
--- a/Src/Newtonsoft.Json/Linq/JTokenReader.cs
+++ b/Src/Newtonsoft.Json/Linq/JTokenReader.cs
@@ -36,57 +36,7 @@ namespace Newtonsoft.Json.Linq
/// </returns>
public override byte[] ReadAsBytes()
{
- Read();
-
- if (IsWrappedInTypeObject())
- {
- byte[] data = ReadAsBytes();
- Read();
- SetToken(JsonToken.Bytes, data);
- return data;
- }
-
- // attempt to convert possible base 64 string to bytes
- if (TokenType == JsonToken.String)
- {
- string s = (string) Value;
- byte[] data = (s.Length == 0) ? new byte[0] : Convert.FromBase64String(s);
- SetToken(JsonToken.Bytes, data);
- }
-
- if (TokenType == JsonToken.Null)
- return null;
- if (TokenType == JsonToken.Bytes)
- return (byte[])Value;
-
- if (TokenType == JsonToken.EndArray)
- return null;
-
- throw CreateReaderException(this, "Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
- }
-
- private bool IsWrappedInTypeObject()
- {
- if (TokenType == JsonToken.StartObject)
- {
- Read();
- if (Value.ToString() == "$type")
- {
- Read();
- if (Value != null && Value.ToString().StartsWith("System.Byte[]"))
- {
- Read();
- if (Value.ToString() == "$value")
- {
- return true;
- }
- }
- }
-
- throw CreateReaderException(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
- }
-
- return false;
+ return ReadAsBytesInternal();
}
/// <summary>
@@ -95,35 +45,7 @@ namespace Newtonsoft.Json.Linq
/// <returns>A <see cref="Nullable{Decimal}"/>. This method will return <c>null</c> at the end of an array.</returns>
public override decimal? ReadAsDecimal()
{
- Read();
-
- if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float)
- {
- SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture));
- return (decimal) Value;
- }
-
- if (TokenType == JsonToken.Null)
- return null;
-
- decimal d;
- if (TokenType == JsonToken.String)
- {
- if (decimal.TryParse((string)Value, NumberStyles.Number, Culture, out d))
- {
- SetToken(JsonToken.Float, d);
- return d;
- }
- else
- {
- throw CreateReaderException(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
- }
- }
-
- if (TokenType == JsonToken.EndArray)
- return null;
-
- throw CreateReaderException(this, "Error reading decimal. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ return ReadAsDecimalInternal();
}
/// <summary>
@@ -132,35 +54,25 @@ namespace Newtonsoft.Json.Linq
/// <returns>A <see cref="Nullable{Int32}"/>. This method will return <c>null</c> at the end of an array.</returns>
public override int? ReadAsInt32()
{
- Read();
-
- if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float)
- {
- SetToken(JsonToken.Integer, Convert.ToInt32(Value, CultureInfo.InvariantCulture));
- return (int)Value;
- }
-
- if (TokenType == JsonToken.Null)
- return null;
-
- int i;
- if (TokenType == JsonToken.String)
- {
- if (int.TryParse((string)Value, NumberStyles.Integer, Culture, out i))
- {
- SetToken(JsonToken.Integer, i);
- return i;
- }
- else
- {
- throw CreateReaderException(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
- }
- }
+ return ReadAsInt32Internal();
+ }
- if (TokenType == JsonToken.EndArray)
- return null;
+ /// <summary>
+ /// Reads the next JSON token from the stream as a <see cref="String"/>.
+ /// </summary>
+ /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
+ public override string ReadAsString()
+ {
+ return ReadAsStringInternal();
+ }
- throw CreateReaderException(this, "Error reading integer. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ /// <summary>
+ /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTime}"/>.
+ /// </summary>
+ /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
+ public override DateTime? ReadAsDateTime()
+ {
+ return ReadAsDateTimeInternal();
}
#if !NET20
@@ -170,37 +82,24 @@ namespace Newtonsoft.Json.Linq
/// <returns>A <see cref="Nullable{DateTimeOffset}"/>. This method will return <c>null</c> at the end of an array.</returns>
public override DateTimeOffset? ReadAsDateTimeOffset()
{
- Read();
-
- if (TokenType == JsonToken.Date)
- {
- SetToken(JsonToken.Date, new DateTimeOffset((DateTime)Value));
- return (DateTimeOffset)Value;
- }
-
- if (TokenType == JsonToken.Null)
- return null;
+ return ReadAsDateTimeOffsetInternal();
+ }
+#endif
- DateTimeOffset dt;
- if (TokenType == JsonToken.String)
+ internal override bool ReadInternal()
+ {
+ if (CurrentState != State.Start)
{
- if (DateTimeOffset.TryParse((string)Value, Culture, DateTimeStyles.None, out dt))
- {
- SetToken(JsonToken.Date, dt);
- return dt;
- }
+ JContainer container = _current as JContainer;
+ if (container != null && _parent != container)
+ return ReadInto(container);
else
- {
- throw CreateReaderException(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
- }
+ return ReadOver(_current);
}
- if (TokenType == JsonToken.EndArray)
- return null;
-
- throw CreateReaderException(this, "Error reading date. Expected date but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
+ SetToken(_current);
+ return true;
}
-#endif
/// <summary>
/// Reads the next JSON token from the stream.
@@ -210,17 +109,9 @@ namespace Newtonsoft.Json.Linq
/// </returns>
public override bool Read()
{
- if (CurrentState != State.Start)
- {
- JContainer container = _current as JContainer;
- if (container != null && _parent != container)
- return ReadInto(container);
- else
- return ReadOver(_current);
- }
+ _readType = ReadType.Read;
- SetToken(_current);
- return true;
+ return ReadInternal();
}
private bool ReadOver(JToken t)
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
index ca9b1fa..42f64b0 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
@@ -92,7 +92,14 @@
<Compile Include="Converters\RegexConverter.cs" />
<Compile Include="Converters\StringEnumConverter.cs" />
<Compile Include="Converters\VersionConverter.cs" />
+ <Compile Include="DateFormatHandling.cs" />
+ <Compile Include="DateTimeZoneHandling.cs" />
+ <Compile Include="FormatterAssemblyStyle.cs" />
+ <Compile Include="Formatting.cs" />
<Compile Include="JsonConstructorAttribute.cs" />
+ <Compile Include="JsonPosition.cs" />
+ <Compile Include="SerializationBinder.cs" />
+ <Compile Include="StreamingContext.cs" />
<Compile Include="Utilities\LinqBridge.cs" />
<Compile Include="Linq\JPath.cs" />
<Compile Include="Linq\JPropertyDescriptor.cs" />
@@ -114,7 +121,6 @@
<Compile Include="ObjectCreationHandling.cs" />
<Compile Include="Converters\IsoDateTimeConverter.cs" />
<Compile Include="Converters\JavaScriptDateTimeConverter.cs" />
- <Compile Include="Converters\JsonDateTimeSerializationMode.cs" />
<Compile Include="Converters\XmlNodeConverter.cs" />
<Compile Include="JsonTextReader.cs" />
<Compile Include="JsonPropertyAttribute.cs" />
@@ -219,6 +225,7 @@
<Compile Include="Utilities\ReflectionUtils.cs" />
<Compile Include="Utilities\StringUtils.cs" />
<Compile Include="Utilities\ValidationUtils.cs" />
+ <Compile Include="WriteState.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj
index 54c0188..22bd2a8 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj
@@ -104,8 +104,15 @@
<Compile Include="Converters\StringEnumConverter.cs" />
<Compile Include="ConstructorHandling.cs" />
<Compile Include="Converters\VersionConverter.cs" />
+ <Compile Include="DateFormatHandling.cs" />
+ <Compile Include="DateTimeZoneHandling.cs" />
+ <Compile Include="FormatterAssemblyStyle.cs" />
+ <Compile Include="Formatting.cs" />
<Compile Include="JsonConstructorAttribute.cs" />
+ <Compile Include="JsonPosition.cs" />
<Compile Include="Linq\JPropertyDescriptor.cs" />
+ <Compile Include="SerializationBinder.cs" />
+ <Compile Include="StreamingContext.cs" />
<Compile Include="Utilities\DynamicProxy.cs" />
<Compile Include="Linq\JPath.cs" />
<Compile Include="Linq\JRaw.cs" />
@@ -133,7 +140,6 @@
<Compile Include="ObjectCreationHandling.cs" />
<Compile Include="Converters\IsoDateTimeConverter.cs" />
<Compile Include="Converters\JavaScriptDateTimeConverter.cs" />
- <Compile Include="Converters\JsonDateTimeSerializationMode.cs" />
<Compile Include="Converters\XmlNodeConverter.cs" />
<Compile Include="JsonTextReader.cs" />
<Compile Include="JsonPropertyAttribute.cs" />
@@ -234,6 +240,7 @@
<Compile Include="Utilities\ReflectionUtils.cs" />
<Compile Include="Utilities\StringUtils.cs" />
<Compile Include="Utilities\ValidationUtils.cs" />
+ <Compile Include="WriteState.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
index 1cd5868..7ea6e09 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
@@ -98,14 +98,16 @@
<Compile Include="Converters\ExpandoObjectConverter.cs" />
<Compile Include="Converters\IsoDateTimeConverter.cs" />
<Compile Include="Converters\JavaScriptDateTimeConverter.cs" />
- <Compile Include="Converters\JsonDateTimeSerializationMode.cs" />
<Compile Include="Converters\KeyValuePairConverter.cs" />
<Compile Include="Converters\RegexConverter.cs" />
<Compile Include="Converters\StringEnumConverter.cs" />
<Compile Include="Converters\VersionConverter.cs" />
<Compile Include="Converters\XmlNodeConverter.cs" />
+ <Compile Include="DateFormatHandling.cs" />
+ <Compile Include="DateTimeZoneHandling.cs" />
<Compile Include="FormatterAssemblyStyle.cs" />
<Compile Include="DefaultValueHandling.cs" />
+ <Compile Include="Formatting.cs" />
<Compile Include="IJsonLineInfo.cs" />
<Compile Include="JsonArrayAttribute.cs" />
<Compile Include="JsonConstructorAttribute.cs" />
@@ -116,6 +118,7 @@
<Compile Include="JsonConverterCollection.cs" />
<Compile Include="JsonIgnoreAttribute.cs" />
<Compile Include="JsonObjectAttribute.cs" />
+ <Compile Include="JsonPosition.cs" />
<Compile Include="JsonPropertyAttribute.cs" />
<Compile Include="JsonReader.cs" />
<Compile Include="JsonReaderException.cs" />
@@ -233,6 +236,7 @@
<Compile Include="Schema\JsonSchemaResolver.cs" />
<Compile Include="Schema\JsonSchemaType.cs" />
<Compile Include="Serialization\JsonTypeReflector.cs" />
+ <Compile Include="WriteState.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj
index 6825dd5..3014bec 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj
@@ -71,14 +71,16 @@
<Compile Include="Converters\ExpandoObjectConverter.cs" />
<Compile Include="Converters\IsoDateTimeConverter.cs" />
<Compile Include="Converters\JavaScriptDateTimeConverter.cs" />
- <Compile Include="Converters\JsonDateTimeSerializationMode.cs" />
<Compile Include="Converters\KeyValuePairConverter.cs" />
<Compile Include="Converters\RegexConverter.cs" />
<Compile Include="Converters\StringEnumConverter.cs" />
<Compile Include="Converters\VersionConverter.cs" />
<Compile Include="Converters\XmlNodeConverter.cs" />
+ <Compile Include="DateFormatHandling.cs" />
+ <Compile Include="DateTimeZoneHandling.cs" />
<Compile Include="FormatterAssemblyStyle.cs" />
<Compile Include="DefaultValueHandling.cs" />
+ <Compile Include="Formatting.cs" />
<Compile Include="IJsonLineInfo.cs" />
<Compile Include="JsonArrayAttribute.cs" />
<Compile Include="JsonConstructorAttribute.cs" />
@@ -89,6 +91,7 @@
<Compile Include="JsonConverterCollection.cs" />
<Compile Include="JsonIgnoreAttribute.cs" />
<Compile Include="JsonObjectAttribute.cs" />
+ <Compile Include="JsonPosition.cs" />
<Compile Include="JsonPropertyAttribute.cs" />
<Compile Include="JsonReader.cs" />
<Compile Include="JsonReaderException.cs" />
@@ -203,6 +206,7 @@
<Compile Include="Schema\JsonSchemaResolver.cs" />
<Compile Include="Schema\JsonSchemaType.cs" />
<Compile Include="Serialization\JsonTypeReflector.cs" />
+ <Compile Include="WriteState.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.CSharp.targets" />
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
index 529ca24..d1b70ad 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
@@ -103,7 +103,11 @@
<Compile Include="Converters\StringEnumConverter.cs" />
<Compile Include="ConstructorHandling.cs" />
<Compile Include="Converters\VersionConverter.cs" />
+ <Compile Include="DateFormatHandling.cs" />
+ <Compile Include="DateTimeZoneHandling.cs" />
+ <Compile Include="Formatting.cs" />
<Compile Include="JsonConstructorAttribute.cs" />
+ <Compile Include="JsonPosition.cs" />
<Compile Include="Utilities\DynamicProxy.cs" />
<Compile Include="Linq\JPath.cs" />
<Compile Include="Linq\JRaw.cs" />
@@ -132,7 +136,6 @@
<Compile Include="ObjectCreationHandling.cs" />
<Compile Include="Converters\IsoDateTimeConverter.cs" />
<Compile Include="Converters\JavaScriptDateTimeConverter.cs" />
- <Compile Include="Converters\JsonDateTimeSerializationMode.cs" />
<Compile Include="Converters\XmlNodeConverter.cs" />
<Compile Include="JsonTextReader.cs" />
<Compile Include="JsonPropertyAttribute.cs" />
@@ -233,6 +236,7 @@
<Compile Include="Utilities\ReflectionUtils.cs" />
<Compile Include="Utilities\StringUtils.cs" />
<Compile Include="Utilities\ValidationUtils.cs" />
+ <Compile Include="WriteState.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
index 0e73afb..32ff8a2 100644
--- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
+++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
@@ -85,7 +85,7 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.0.8.0")]
#if !PocketPC
-[assembly: AssemblyFileVersion("4.0.8.14625")]
+[assembly: AssemblyFileVersion("4.0.8.14704")]
#endif
[assembly: CLSCompliant(true)]
diff --git a/Src/Newtonsoft.Json/Serialization/JsonContract.cs b/Src/Newtonsoft.Json/Serialization/JsonContract.cs
index 9dd8532..db38243 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonContract.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonContract.cs
@@ -47,17 +47,6 @@ namespace Newtonsoft.Json.Serialization
Linq
}
- internal enum ReadType
- {
- Read,
- ReadAsInt32,
- ReadAsDecimal,
- ReadAsBytes,
-#if !NET20
- ReadAsDateTimeOffset
-#endif
- }
-
/// <summary>
/// Contract details for a <see cref="Type"/> used by the <see cref="JsonSerializer"/>.
/// </summary>
@@ -204,6 +193,14 @@ namespace Newtonsoft.Json.Serialization
{
InternalReadType = ReadType.ReadAsDecimal;
}
+ else if (NonNullableUnderlyingType == typeof(string))
+ {
+ InternalReadType = ReadType.ReadAsString;
+ }
+ else if (NonNullableUnderlyingType == typeof(DateTime))
+ {
+ InternalReadType = ReadType.ReadAsDateTime;
+ }
#if !NET20
else if (NonNullableUnderlyingType == typeof(DateTimeOffset))
{
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
index 40054cc..2a81a8a 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
@@ -1134,6 +1134,12 @@ namespace Newtonsoft.Json.Serialization
case ReadType.ReadAsBytes:
reader.ReadAsBytes();
break;
+ case ReadType.ReadAsString:
+ reader.ReadAsString();
+ break;
+ case ReadType.ReadAsDateTime:
+ reader.ReadAsDateTime();
+ break;
#if !NET20
case ReadType.ReadAsDateTimeOffset:
reader.ReadAsDateTimeOffset();
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs
index d73090c..f35343c 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs
@@ -24,6 +24,7 @@
#endregion
using System;
+using System.Globalization;
using System.Runtime.Serialization.Formatters;
using Newtonsoft.Json.Utilities;
using System.Runtime.Serialization;
@@ -125,6 +126,24 @@ namespace Newtonsoft.Json.Serialization
set { _serializer.Context = value; }
}
+ public override Formatting Formatting
+ {
+ get { return _serializer.Formatting; }
+ set { _serializer.Formatting = value; }
+ }
+
+ public override DateFormatHandling DateFormatHandling
+ {
+ get { return _serializer.DateFormatHandling; }
+ set { _serializer.DateFormatHandling = value; }
+ }
+
+ public override DateTimeZoneHandling DateTimeZoneHandling
+ {
+ get { return _serializer.DateTimeZoneHandling; }
+ set { _serializer.DateTimeZoneHandling = value; }
+ }
+
internal JsonSerializerInternalBase GetInternalSerializer()
{
if (_serializerReader != null)
diff --git a/Src/Newtonsoft.Json/WriteState.cs b/Src/Newtonsoft.Json/WriteState.cs
new file mode 100644
index 0000000..8bfc577
--- /dev/null
+++ b/Src/Newtonsoft.Json/WriteState.cs
@@ -0,0 +1,41 @@
+using System;
+
+namespace Newtonsoft.Json
+{
+ /// <summary>
+ /// Specifies the state of the <see cref="JsonWriter"/>.
+ /// </summary>
+ public enum WriteState
+ {
+ /// <summary>
+ /// An exception has been thrown, which has left the <see cref="JsonWriter"/> in an invalid state.
+ /// You may call the <see cref="JsonWriter.Close"/> method to put the <see cref="JsonWriter"/> in the <c>Closed</c> state.
+ /// Any other <see cref="JsonWriter"/> method calls results in an <see cref="InvalidOperationException"/> being thrown.
+ /// </summary>
+ Error,
+ /// <summary>
+ /// The <see cref="JsonWriter.Close"/> method has been called.
+ /// </summary>
+ Closed,
+ /// <summary>
+ /// An object is being written.
+ /// </summary>
+ Object,
+ /// <summary>
+ /// A array is being written.
+ /// </summary>
+ Array,
+ /// <summary>
+ /// A constructor is being written.
+ /// </summary>
+ Constructor,
+ /// <summary>
+ /// A property is being written.
+ /// </summary>
+ Property,
+ /// <summary>
+ /// A write method has not been called.
+ /// </summary>
+ Start
+ }
+} \ No newline at end of file