-Added JsonReader.ReadAsDateTimeOffset

-Fixed losing timezone information when deserializing DateTimeOffsets
This commit is contained in:
JamesNK
2010-09-12 03:39:39 +00:00
parent 11ce71ee8b
commit 235770442a
9 changed files with 245 additions and 30 deletions
@@ -60,6 +60,13 @@ namespace Newtonsoft.Json.Tests.Converters
Assert.AreEqual("new Date(976918263055)", result);
}
[Test]
public void sdfs()
{
int i = Convert.ToInt32("+1");
Console.WriteLine(i);
}
[Test]
public void SerializeNullableDateTimeClass()
{
@@ -692,5 +692,95 @@ bye", reader.Value);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
}
#if !NET20
[Test]
public void ReadAsDateTimeOffset()
{
string json = "{\"Offset\":\"\\/Date(946663200000+0600)\\/\"}";
JsonTextReader reader = new JsonTextReader(new StringReader(json));
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
reader.ReadAsDateTimeOffset();
Assert.AreEqual(JsonToken.Date, reader.TokenType);
Assert.AreEqual(typeof(DateTimeOffset), reader.ValueType);
Assert.AreEqual(new DateTimeOffset(new DateTime(2000, 1, 1), TimeSpan.FromHours(6)), reader.Value);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
}
[Test]
public void ReadAsDateTimeOffsetNegative()
{
string json = @"{""Offset"":""\/Date(946706400000-0600)\/""}";
JsonTextReader reader = new JsonTextReader(new StringReader(json));
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
reader.ReadAsDateTimeOffset();
Assert.AreEqual(JsonToken.Date, reader.TokenType);
Assert.AreEqual(typeof(DateTimeOffset), reader.ValueType);
Assert.AreEqual(new DateTimeOffset(new DateTime(2000, 1, 1), TimeSpan.FromHours(-6)), reader.Value);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
}
[Test]
public void ReadAsDateTimeOffsetHoursOnly()
{
string json = "{\"Offset\":\"\\/Date(946663200000+06)\\/\"}";
JsonTextReader reader = new JsonTextReader(new StringReader(json));
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
reader.ReadAsDateTimeOffset();
Assert.AreEqual(JsonToken.Date, reader.TokenType);
Assert.AreEqual(typeof(DateTimeOffset), reader.ValueType);
Assert.AreEqual(new DateTimeOffset(new DateTime(2000, 1, 1), TimeSpan.FromHours(6)), reader.Value);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
}
[Test]
public void ReadAsDateTimeOffsetWithMinutes()
{
string json = @"{""Offset"":""\/Date(946708260000-0631)\/""}";
JsonTextReader reader = new JsonTextReader(new StringReader(json));
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
reader.ReadAsDateTimeOffset();
Assert.AreEqual(JsonToken.Date, reader.TokenType);
Assert.AreEqual(typeof(DateTimeOffset), reader.ValueType);
Assert.AreEqual(new DateTimeOffset(new DateTime(2000, 1, 1), TimeSpan.FromHours(-6).Add(TimeSpan.FromMinutes(-31))), reader.Value);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
}
#endif
}
}
@@ -3539,24 +3539,26 @@ keyword such as type of business.""
Assert.AreEqual(int.MaxValue, newStruct.MyInt);
}
//public class TimeZoneOffsetObject
//{
// public DateTimeOffset Offset { get; set; }
//}
public class TimeZoneOffsetObject
{
public DateTimeOffset Offset { get; set; }
}
//[Test]
//public void ReadWriteTimeZoneOffset()
//{
// var serializeObject = JsonConvert.SerializeObject(new TimeZoneOffsetObject
// {
// Offset = new DateTimeOffset(new DateTime(2000, 1, 1), TimeSpan.FromHours(6))
// });
#if !NET20
[Test]
public void ReadWriteTimeZoneOffset()
{
var serializeObject = JsonConvert.SerializeObject(new TimeZoneOffsetObject
{
Offset = new DateTimeOffset(new DateTime(2000, 1, 1), TimeSpan.FromHours(6))
});
// Assert.AreEqual("{\"Offset\":\"\\/Date(946663200000+0600)\\/\"}", serializeObject);
// var deserializeObject = JsonConvert.DeserializeObject<TimeZoneOffsetObject>(serializeObject);
// Assert.AreEqual(TimeSpan.FromHours(6), deserializeObject.Offset.Offset); // fails here
// Assert.AreEqual(new DateTime(2000, 1, 1), deserializeObject.Offset.Date);
//}
Assert.AreEqual("{\"Offset\":\"\\/Date(946663200000+0600)\\/\"}", 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);
}
#endif
public abstract class LogEvent
{
+17
View File
@@ -150,6 +150,23 @@ namespace Newtonsoft.Json.Bson
return (byte[])Value;
}
#if !NET20
/// <summary>
/// Reads the next JSON token from the stream as a <see cref="DateTimeOffset"/>.
/// </summary>
/// <returns>
/// A <see cref="DateTimeOffset"/>.
/// </returns>
public override DateTimeOffset ReadAsDateTimeOffset()
{
Read();
if (TokenType != JsonToken.Date)
throw new JsonReaderException("Error reading date. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
return new DateTimeOffset((DateTime)Value);
}
#endif
/// <summary>
/// Reads the next JSON token from the stream.
/// </summary>
+8
View File
@@ -210,6 +210,14 @@ namespace Newtonsoft.Json
/// <returns>A <see cref="T:Byte[]"/> or a null reference if the next JSON token is null.</returns>
public abstract byte[] ReadAsBytes();
#if !NET20
/// <summary>
/// Reads the next JSON token from the stream as a <see cref="DateTimeOffset"/>.
/// </summary>
/// <returns>A <see cref="DateTimeOffset"/>.</returns>
public abstract DateTimeOffset ReadAsDateTimeOffset();
#endif
/// <summary>
/// Skips the children of the current token.
/// </summary>
+64 -13
View File
@@ -41,7 +41,10 @@ namespace Newtonsoft.Json
private enum ReadType
{
Read,
ReadAsBytes
ReadAsBytes,
#if !NET20
ReadAsDateTimeOffset
#endif
}
private readonly TextReader _reader;
@@ -190,6 +193,22 @@ namespace Newtonsoft.Json
return new JsonReaderException(message, null, _currentLineNumber, _currentLinePosition);
}
private TimeSpan ReadOffset(string offsetText)
{
bool negative = (offsetText[0] == '-');
int hours = int.Parse(offsetText.Substring(1, 2), NumberStyles.Integer, CultureInfo.InvariantCulture);
int minutes = 0;
if (offsetText.Length >= 5)
minutes = int.Parse(offsetText.Substring(3, 2), NumberStyles.Integer, CultureInfo.InvariantCulture);
TimeSpan offset = TimeSpan.FromHours(hours) + TimeSpan.FromMinutes(minutes);
if (negative)
offset = offset.Negate();
return offset;
}
private void ParseDate(string text)
{
string value = text.Substring(6, text.Length - 8);
@@ -200,30 +219,44 @@ namespace Newtonsoft.Json
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);
DateTime dateTime;
switch (kind)
#if !NET20
if (_readType == ReadType.ReadAsDateTimeOffset)
{
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, new DateTimeOffset(utcDateTime.Add(offset).Ticks, offset));
}
else
#endif
{
DateTime dateTime;
SetToken(JsonToken.Date, 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);
}
}
private const int LineFeedValue = StringUtils.LineFeed;
@@ -299,6 +332,24 @@ namespace Newtonsoft.Json
throw CreateJsonReaderException("Unexpected token when reading bytes: {0}. Line {1}, position {2}.", TokenType, _currentLineNumber, _currentLinePosition);
}
#if !NET20
/// <summary>
/// Reads the next JSON token from the stream as a <see cref="DateTimeOffset"/>.
/// </summary>
/// <returns>A <see cref="DateTimeOffset"/>.</returns>
public override DateTimeOffset ReadAsDateTimeOffset()
{
_readType = ReadType.ReadAsDateTimeOffset;
if (!ReadInternal())
throw CreateJsonReaderException("Unexpected end when reading date: Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
if (TokenType == JsonToken.Date)
return (DateTimeOffset)Value;
throw CreateJsonReaderException("Unexpected token when reading date: {0}. Line {1}, position {2}.", TokenType, _currentLineNumber, _currentLinePosition);
}
#endif
private bool ReadInternal()
{
while (true)
@@ -318,6 +318,20 @@ namespace Newtonsoft.Json
return data;
}
#if !NET20
/// <summary>
/// Reads the next JSON token from the stream as a <see cref="DateTimeOffset"/>.
/// </summary>
/// <returns>A <see cref="DateTimeOffset"/>.</returns>
public override DateTimeOffset ReadAsDateTimeOffset()
{
DateTimeOffset dateTimeOffset = _reader.ReadAsDateTimeOffset();
ValidateCurrentToken();
return dateTimeOffset;
}
#endif
/// <summary>
/// Reads the next JSON token from the stream.
/// </summary>
+16
View File
@@ -54,6 +54,22 @@ namespace Newtonsoft.Json.Linq
throw new JsonReaderException("Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
}
#if !NET20
/// <summary>
/// Reads the next JSON token from the stream as a <see cref="DateTimeOffset"/>.
/// </summary>
/// <returns>A <see cref="DateTimeOffset"/>.</returns>
public override DateTimeOffset ReadAsDateTimeOffset()
{
Read();
if (TokenType == JsonToken.Date)
return new DateTimeOffset((DateTime)Value);
throw new JsonReaderException("Error reading date. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
}
#endif
/// <summary>
/// Reads the next JSON token from the stream.
/// </summary>
@@ -928,10 +928,20 @@ namespace Newtonsoft.Json.Serialization
continue;
}
if (property.PropertyType == typeof(byte[]))
// don't read properties with converters as a specific value
// the value might be a string which will then get converted which will error if read as date for example
bool hasConverter = (GetConverter(GetContractSafe(property.PropertyType), property.Converter) != null);
if (property.PropertyType == typeof(byte[]) && !hasConverter)
{
reader.ReadAsBytes();
}
#if !NET20
else if (property.PropertyType == typeof(DateTimeOffset) && !hasConverter)
{
reader.ReadAsDateTimeOffset();
}
#endif
else
{
if (!reader.Read())