Skip to content

Nullable DateTime does not deserialize correctly #98

Closed

Description

@LeapingGorilla

Attempting to deserialise a string containing a date into an object where the field is a Nullable<DateTime> results in a FormatException with the error:

String was not recognized as a valid DateTime.
at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
at System.DateTime.Parse(String s, IFormatProvider provider, DateTimeStyles styles)>
at NetJSON.NetJSON.FastStringToDate(String value)
at FailingClassClass.ExtractNullableDateTime(Char* , Int32& )
at FailingClassClass.CreateClassOrDictFailingClass(Char* , Int32& )
at FailingClassClass.ReadFailingClass(String )
at FailingClassClass.Deserialize(String )
at NetJSON.NetJSON.Deserialize[T](String json)

A minimal repro is:

void Main()
{
    var failing = new FailingClass { ThisGoesBang = new DateTime(2015, 12, 25, 16, 30, 00) };
    var failStr = NetJSON.NetJSON.Serialize(failing);
    Console.WriteLine(failStr);
    var failResult = NetJSON.NetJSON.Deserialize<FailingClass>(failStr); // Never get past here, we explode with a FormatException  
    Console.WriteLine("FailingClass Field is Correct? - {0}", failing.ThisGoesBang == failResult.ThisGoesBang);
}

public class FailingClass
{
    public DateTime? ThisGoesBang { get; set; }
}

Activity

  1. rpgmaker commented on Dec 17, 2015

    @rpgmaker
    Owner

    Thanks for the find. Could you try to do similar with nullable long.

    Thanks,

  2. LeapingGorilla commented on Dec 17, 2015

    @LeapingGorilla
    ContributorAuthor

    I wrote a simple console app to test out as many common value types as I could think of. The FormatException appears when we use a nullable for:

    • DateTime
    • TimeSpan
    • Guid

    long, int, short (and their unsigned variants), float, double, decimal, byte, sbyte, enum and bool are fine.

    I've attached a LinqPad script which I used to run the tests: NetJSOn Tests.zip

    The exceptions with strings for deserialization for the failed types are:

    Type: System.DateTime - Fail. Serialised JSON - {"TestItem":"/Date(14501376000000000)/"}
    Exception: System.FormatException: String was not recognized as a valid DateTime.
    at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
    at System.DateTime.Parse(String s, IFormatProvider provider, DateTimeStyles styles)
    at NetJSON.NetJSON.FastStringToDate(String value)
    at TestType1DateTimeClass.ExtractNullableDateTime(Char* , Int32& ) at TestType1DateTimeClass.CreateClassOrDictTestTypeDateTime(Char* , Int32& )
    at TestType1DateTimeClass.ReadTestTypeDateTime(String ) at TestType1DateTimeClass.Deserialize(String )
    at DeserializeUserQuery+TestType`1[System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
    at NetJSON.NetJSON.Deserialize(Type type, String value)
    at UserQuery.TestSerialisation[T](T value) in query_byzzwm.cs:line 92

    Type: System.TimeSpan - Fail. Serialised JSON - {"TestItem":"00:00:00.0001500"}
    Exception: System.FormatException: String was not recognized as a valid TimeSpan.
    at System.Globalization.TimeSpanParse.TimeSpanResult.SetFailure(ParseFailureKind failure, String failureMessageID, Object > failureMessageFormatArgument, String failureArgumentName)
    at System.Globalization.TimeSpanParse.ProcessTerminal_HMS_F_D(TimeSpanRawInfo& raw, TimeSpanStandardStyles style, TimeSpanResult& result)
    at System.Globalization.TimeSpanParse.ProcessTerminalState(TimeSpanRawInfo& raw, TimeSpanStandardStyles style, TimeSpanResult& result)
    at System.Globalization.TimeSpanParse.TryParseTimeSpan(String input, TimeSpanStandardStyles style, IFormatProvider formatProvider, TimeSpanResult& > result)
    at System.Globalization.TimeSpanParse.Parse(String input, IFormatProvider formatProvider)
    at TestType1TimeSpanClass.ExtractNullableTimeSpan(Char* , Int32& ) at TestType1TimeSpanClass.CreateClassOrDictTestTypeTimeSpan(Char* , Int32& )
    at TestType1TimeSpanClass.ReadTestTypeTimeSpan(String ) at TestType1TimeSpanClass.Deserialize(String )
    at DeserializeUserQuery+TestType`1[System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
    at NetJSON.NetJSON.Deserialize(Type type, String value)
    at UserQuery.TestSerialisation[T](T value) in query_byzzwm.cs:line 92

    Type: System.Guid - Fail. Serialised JSON - {"TestItem":"10b5a72b-815f-4e64-90bf-cb250840e989"}
    Exception: System.FormatException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
    at System.Guid.GuidResult.SetFailure(ParseFailureKind failure, String failureMessageID, Object failureMessageFormatArgument, String > failureArgumentName, Exception innerException)
    at System.Guid.TryParseGuidWithDashes(String guidString, GuidResult& result)
    at System.Guid.TryParseGuid(String g, GuidStyles flags, GuidResult& result)
    at System.Guid..ctor(String g)
    at TestType1GuidClass.ExtractNullableGuid(Char* , Int32& ) at TestType1GuidClass.CreateClassOrDictTestTypeGuid(Char* , Int32& )
    at TestType1GuidClass.ReadTestTypeGuid(String ) at TestType1GuidClass.Deserialize(String )
    at DeserializeUserQuery+TestType`1[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
    at NetJSON.NetJSON.Deserialize(Type type, String value)
    at UserQuery.TestSerialisation[T](T value) in query_byzzwm.cs:line 92

  3. rpgmaker commented on Dec 18, 2015

    @rpgmaker
    Owner

    What is interesting is that all the values shows are actually valid for their types. I wonder if it is passing additional text/string into the method when ever they are nullable such as quotes. I will look into and get back to you thanks. Thanks for the sample tests :)

    Thanks

  4. LeapingGorilla commented on Dec 18, 2015

    @LeapingGorilla
    ContributorAuthor

    The root of the bug seems to be that the string that is passed to the constructor for Guid, DateTime and TimeSpan still contains a leading and trailing quote. To take Guid as an example, the string passed into FastStringToGuid should be: "10b5a72b-815f-4e64-90bf-cb250840e989" but is actually "\"10b5a72b-815f-4e64-90bf-cb250840e989\""

  5. rpgmaker commented on Dec 18, 2015

    @rpgmaker
    Owner

    Can you please confirm if it is working?

    Thanks,

  6. LeapingGorilla commented on Dec 18, 2015

    @LeapingGorilla
    ContributorAuthor

    Confirmed as fixed in NuGet package 1.0.15.5. Nice work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions