-Added JsonReader.ReadAsDateTimeOffset
-Fixed losing timezone information when deserializing DateTimeOffsets
This commit is contained in:
@@ -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
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user