EvaHHHH
EvaHHHH

Reputation: 353

Could not convert string to DateTime and The field is required in NewtonSoftJson

I try pass data below.

{
  "Name": "Test",
  "Date": "1631149200826"
}

My Class as below:

public class MyClass
{
    public string Name { get; set; }
    public int qty { get; set; }
    public DateTime Date { get; set; }
}

Everything works fine when using .NET Framework.

But I got 2 error when using .NET Core 3.1 and Microsoft.AspNetCore.Mvc.NewtonsoftJson 3.1.8.

error1:Could not convert string to DateTime: 1631149200826. Path 'data.Date'

error2:The Item field is required.

I know it could solve error2 if I add some "ignore property" on my class.

But I wonder if there are other solution?

For example, add some options on controller?

services.AddControllers().AddNewtonsoftJson().AddJsonOptions();

Upvotes: 1

Views: 2974

Answers (2)

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131641

The standard date format in JSON is ISO8601, ie 2021-09-09T10:52:01+00:00 or 2021-09-09T10:52:01Z. JSON.NET never parsed raw numbers as dates. As the docs explain:

The default format used by Json.NET is the ISO 8601 standard: "2012-03-19T07:22Z".

Prior to Json.NET 4.5 dates were written using the Microsoft format: "/Date(1198908717056)/". If you want to use this format, or you want to maintain compatibility with Microsoft JSON serializers or older versions of Json.NET, then change the DateFormatHandling setting to MicrosoftDateFormat.

The only way "1631149200826" can be converted to a DateTime is through a custom type converter.

The correct solution would be to switch to the standard date format.

If you want to keep using JSON.NET, you'll have to add the custom type converter that handled "1631149200826".

It's possible to create a custom DateTime converter for System.Text.Json as well. It's used in a similar way as JSON.NET custom converters, either through serializer options or though JSON attibutes.

In this case, the converter could be:

public class DateTimeMilliJsonConverter : JsonConverter<DateTime>
{
    public override DateTime Read(
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options) 
    {
        long millis=long.Parse(reader.GetString());
        return DateTime.UnixEpoch.AddMilliseconds(millis);
    }

    public override void Write(
        Utf8JsonWriter writer,
        DateTime dateTimeValue,
        JsonSerializerOptions options)
    {
        long millis=(long)dateTimeValue.Subtract(DateTime.UnixEpoch).TotalMilliseconds;
        writer.WriteStringValue(millis.ToString());
    }
}

The converter can be applied to a property through the JsonConverter attribute

public class MyClass
{
    public string Name { get; set; }
    public int qty { get; set; }

    [JsonConverter(typeof(DateTimeOffsetJsonConverter))]
    public DateTime Date { get; set; }
}

Upvotes: 1

Martin Staufcik
Martin Staufcik

Reputation: 9492

Supposing the Date value is the number of milliseconds since the start of epoch, you could do something similar to this:

public class MyClass
{
    public string Name { get; set; }
    public int qty { get; set; }

    [JsonProperty("Date")]
    public long DateAsMilliseconds { get; set; }

    [JsonIgnore]
    public DateTime Date => TimeUtils.UnixMillisecondsToDateTime(DateAsMilliseconds);
}

public class TimeUtils
{
    public static DateTime UnixMillisecondsToDateTime(double unixTimeStamp)
    {
        DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
        dateTime = dateTime.AddMilliseconds(unixTimeStamp).ToLocalTime();
        return dateTime;
    }
}

Update: as suggested in the comments a far better idea would be to use the standard date format ISO8601.

Upvotes: 1

Related Questions