Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get JSON.NET to serialize date/time to ISO 8601?

I have a Web API application that returns JSON to consumers who may not be using Microsoft technologies. When my controller returns an object with DateTime properties as JSON, it serializes the date in this format:

2017-03-15T00:00:00-04:00

This is giving the consumer a bit of a headache as they're expect it to be in ISO 8601 format. Some research has told me that JSON.NET now uses ISO 8601 by default (I am using 9.0.1). When I run this code...

Clipboard.Copy(JsonConvert.SerializeObject(DateTime.Now));

...I get this:

2017-03-15T09:10:13.8105498-04:00

Wikipedia shows these as valid ISO 8601 formats when expressing full date and time:

2017-03-15T11:45:42+00:00
2017-03-15T11:45:42Z
20170315T114542Z

However, the output I got above doesn't exactly match any of those. I want the formatter to use 2017-03-15T11:45:42Z.

And probably worthy of another question altogether, adding the below line in my Web API config seems to be ignored as it continues to return JSON in the date originally shown above:

config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IsoDateTimeConverter());

I assume that once I figure out the core issue, the Web API issue may also be resolved.

like image 596
oscilatingcretin Avatar asked Mar 15 '17 13:03

oscilatingcretin


People also ask

How do I format a date in ISO 8601?

ISO 8601 represents date and time by starting with the year, followed by the month, the day, the hour, the minutes, seconds and milliseconds. For example, 2020-07-10 15:00:00.000, represents the 10th of July 2020 at 3 p.m. (in local time as there is no time zone offset specified—more on that below).

Does JSON accept datetime?

Json library parses and writes DateTime and DateTimeOffset values according to the ISO 8601-1:2019 extended profile.

How does JSON format handle dates?

JSON does not have a built-in type for date/time values. The general consensus is to store the date/time value as a string in ISO 8601 format.


3 Answers

The format you are getting is ISO 8601 format (read the section on Times and Time Zone Designators in Wikipedia), it's just that your dates are apparently not adjusted to UTC time, so you are getting a timezone offset appended to the date rather than the Z Zulu timezone indicator.

The IsoDateTimeConverter has settings you can use to customize its output. You can make it automatically adjust dates to UTC by setting DateTimeStyles to AdjustToUniversal. You can also customize the output format to omit the fractional seconds if you don't want them. By default, the converter does not adjust to UTC time and includes as many decimals of precision as there are available for the seconds.

Try this:

IsoDateTimeConverter converter = new IsoDateTimeConverter {     DateTimeStyles = DateTimeStyles.AdjustToUniversal,     DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssK" };  config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(converter); 

If your dates are already UTC, but the DateTimeKind on them is not set to Utc like it should be (e.g. it is Unspecified), then ideally you should fix your code so that this indicator is set correctly prior to serializing. However, if you can't (or don't want to) do that, you can work around it by changing the converter settings to always include the Z indicator in the date format (instead of using the K specifier which looks at the DateTimeKind on the date) and removing the AdjustToUniversal directive.

IsoDateTimeConverter converter = new IsoDateTimeConverter {     DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'" }; 
like image 92
Brian Rogers Avatar answered Sep 28 '22 02:09

Brian Rogers


Adding to @Brian Rogers' answer, for ASP Core, add in Startup.cs:

services.AddMvc()   .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)   .AddJsonOptions(options =>     options.SerializerSettings.Converters.Add(new IsoDateTimeConverter     {       DateTimeStyles = DateTimeStyles.AdjustToUniversal     })); 
like image 33
Assaf S. Avatar answered Sep 28 '22 01:09

Assaf S.


Another option:

string json = JsonConvert.SerializeObject(DateTime.Now, new JsonSerializerSettings
{
     DateTimeZoneHandling = DateTimeZoneHandling.Utc
});
like image 24
OfirD Avatar answered Sep 28 '22 01:09

OfirD