14

In researching how to deserialize a TimeSpan using Newtonsoft's JSON.net I came across code in my current project that did not use Json.net. It used System.Text.Json.JsonSerializer and appeared to not fail on the operation of deserializing the TimeSpan property, as per the unit tests I was running.

Great I thought, .Net Core 3.1 has surpassed the historical issue of deserializing a TimeSpan and all is good. So fired up a test case in the latest version of Linqpad 6 (which uses .NET Core) to verify and to my chagrin it failed.


So the question is, can the TimeSpan be serialized/deserialized using either library (and if so how)… or is my test case below flawed in some respect?


Code

public class Project { public TimeSpan AverageScanTime { get; set; } }

Linqpad C# Code

var newP = new Project() { AverageScanTime = TimeSpan.FromHours(1) };

newP.Dump("New one");

var json = System.Text.Json.JsonSerializer.Serialize(newP);

json.Dump("JSON serialized");

System.Text.Json.JsonSerializer.Deserialize<Project>(json)
                               .Dump("JSON Deserialize");

Deserialize Failure

enter image description here

dbc
  • 104,963
  • 20
  • 228
  • 340
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
  • 2
    Looks like a duplicate of [.Net Core 3.0 TimeSpan deserialization erro](https://stackoverflow.com/q/58283761/3744182), agree? – dbc Jan 02 '20 at 00:20
  • @dbc No, because that answer states that .NET core's json processing was *in-part* created to handle timespan but that not all timespan's are the same. I am talking a .Net's timespan as an input and it is failing.... – ΩmegaMan Jan 02 '20 at 14:15
  • 2
    *that answer states that .NET core's json processing was in-part created to handle timespan* - I don't see that. The answer states, *The REST API service shouldn't produce such a JSON string.* What's happening here is that the new serializer is just serializing all the properties of `TimeSpan` as a JSON object because it has no special case for that structure, then later failing to deserialize because all those properties are immutable. A `JsonConverter` like the one at the linked answer should resolve the issue. – dbc Jan 02 '20 at 16:09
  • Fixed in .NET 6.0 https://stackoverflow.com/a/69409726/11375591 – Igor Mar 24 '22 at 14:24

3 Answers3

23

JsonSerializer for TimeSpan seem will added in Future (removed from .NET 6 milestone). You can trace this issue in Future milestone or this issue.

Before the end of 2022, you need implement JsonTimeSpanConverter on your own. Or you can install Macross.Json.Extensions nuget package and follow the instruction to de/serializer.

At this time, with .NET 6, you can use the build-in Serialize method to serialize and deserialize objects. As below:

System.Text.Json.JsonSerializer.Serialize(
    new { Time = TimeSpan.FromSeconds(100) }
);
// Output:
// {"Time":"00:01:40"}
Poy Chang
  • 1,106
  • 1
  • 10
  • 13
  • 7
    Sadly, it has not been added to .NET Core 5. [Source](https://github.com/dotnet/runtime/issues/29932#issuecomment-694650687) – robalem Dec 21 '20 at 10:14
  • As of today it is moved to ["Future"](https://github.com/dotnet/runtime/issues/24601#issuecomment-856321283), so not in .Net 6 either. – Anrijs Vītoliņš Feb 18 '22 at 14:10
5

An addition to the answer from Poy Chang

Swagger (Swashbuckle) also requires a configuration

services.AddSwaggerGen(options =>
{
    options.MapType(typeof(TimeSpan), () => new OpenApiSchema
    {
        Type = "string",
        Example = new OpenApiString("00:00:00")
    });
});
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
live2
  • 3,771
  • 2
  • 37
  • 46
4

TimeSpanConverter is available in .NET 6.0. So TimeSpan serialization/deserialization will work without custom converters out of the box.

Issue: https://github.com/dotnet/runtime/issues/29932

Implementation: https://github.com/dotnet/runtime/pull/54186

Igor
  • 349
  • 1
  • 6
  • 1
    How about an example of it working. – ΩmegaMan Mar 24 '22 at 13:50
  • I don't think this is necessary for obvious code. But I agree with you that we can't believe everything that is written on the Internet and need to check everything)) https://dotnetfiddle.net/13kIUo – Igor Mar 24 '22 at 14:20
  • That is what happened with .Net 2/3, it kept getting reported that it now works...but it didn't. If you do have the example, that would be great. – ΩmegaMan Mar 24 '22 at 15:44
  • I'm not sure I understand you. An example of what do you want? A working example for .NET 6.0 is here https://dotnetfiddle.net/13kIUo There is no built-in converter for the TimeSpan type in .NET 5.0 and .NET Core 3.1/3.0. – Igor Mar 25 '22 at 01:34