Reputation: 2103
We are sending JSON to an API defined by swagger that some properties are DateTime in the format yyyy-MM-ddThh:mm:ss.000Z (the milliseconds must be 3 digits or it fails validation at the endpoint) and some are Date (no time) properties.
I have seen many messages saying use the formatters like this:
var jsonSettings = new JsonSerializerSettings();
jsonSettings.DateFormatString = "yyyy-MM-ddThh:mm:ss.000Z"; //try .fffZ too
var jsonObject= Newtonsoft.Json.JsonConvert.DeserializeObject<OurSwaggerObject>(json , setting);
but this does not convert the DateTimes into the correct format, and how does C# deal with a Date only type? It always seems to serialise as DateTime.MinValue()
Here is an example:
Someone sends me json as string but the the dates and datetimes in the incorrect format to be sent to the endpoint. I was hoping that the swagger class and json deserialisation would format them but it is not.
This is the swagger generated class
public class OurSwaggerObject
{
[Newtonsoft.Json.JsonProperty("dateTimeField", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required]
[System.ComponentModel.DataAnnotations.RegularExpression(@"^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$")]
public DateTime dateTimeField { get; set; }
[Newtonsoft.Json.JsonProperty("dateField", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required]
[System.ComponentModel.DataAnnotations.RegularExpression(@"^\d{4}-\d\d-\d\d$")]
public DateTime dateField { get; set; }
}
So I try and coerce the json to be correct but I'm doing it wrong or something is missing
string json = @"{ 'dateTimeField': '1995-04-07T00:00:00',
'dateField': '1995-04-07T00:00:00'
}";
/* The json we need to satisfy the swagger endpoint is:
{ 'dateTimeField': '1995-04-07T00:00:00.000Z',
'dateField': '1995-04-07'
}
*/
OurSwaggerObject deserialisedIntoObject = Newtonsoft.Json.JsonConvert.DeserializeObject<OurSwaggerObject>(json);
string serialisedToString = Newtonsoft.Json.JsonConvert.SerializeObject(deserialisedIntoObject);
//serialisedToString= "{\"dateTimeField\":\"1995-04-07T00:00:00\",\"dateField\":\"1995-04-07T00:00:00\"}"
var jsonSettings = new JsonSerializerSettings();
jsonSettings.DateFormatString = "yyyy-MM-ddThh:mm:ss.fffZ"; //this won't help much for the 'date' only field!
deserialisedIntoObject = Newtonsoft.Json.JsonConvert.DeserializeObject<OurSwaggerObject>(json,jsonSettings);
serialisedToString = Newtonsoft.Json.JsonConvert.SerializeObject(deserialisedIntoObject, jsonSettings);
//serialisedToString="{\"dateTimeField\":\"1995-04-07T00:00:00\",\"dateField\":\"1995-04-07T00:00:00\"}"
Upvotes: 57
Views: 210366
Reputation: 131423
Update - 2024
By now, ISO8601 is the actual standard way of specifying date in JSON, defined in RFC 7493
It is RECOMMENDED that all such data items be expressed as string values in ISO 8601 format, as specified in RFC3339, with the additional restrictions that uppercase rather than lowercase letters be used, that the timezone be included not defaulted, and that optional trailing seconds be included even when their value is "00".
RFC3399 specifies that fractional seconds are optional. The timezone is also optional in RFC3399 but required in JSON according to RFC7492:
time-fraction = ("," / ".") 1*DIGIT
time-numoffset = ("+" / "-") time-hour [[":"] time-minute]
time-zone = "Z" / time-numoffset
...
time = timespec-base [time-fraction] [time-zone]
.NET 6 introduced DateOny and TimeOnly which, by now, are supported in ASP.NET Core, System.Text.Json and EF Core.
This snippet :
record Test(DateOnly date,TimeOnly time);
...
var test=new Test(new DateOnly(2024,10,19),new TimeOnly(21,34))
var json=JsonSerializer.Serialize(text);
Produces
{"date":"2024-10-19","time":"21:34:00"}
JSON.NET's JsonConvert.SerializeObject(test);
produces the same string
Original Answer
As I mentioned in a comment, there is no standard date representation in JSON. The ISO8601 is the de-facto standard, ie most people started using this some years ago. ISO8601 does not require milliseconds. If the other endpoint requires them, it's violating the defacto standard.
Json.NET has been using IOS8601 since version 4.5. The current one is 10.0.3. The following code:
JsonConvert.SerializeObject(DateTime.Now)
returns
"2017-09-08T19:01:55.714942+03:00"
On my machine. Notice the timezone offset. That's also part of the standard. Z
means UTC.
You can specify your own time format, provided it's the correct one. In this case, it should be yyyy-MM-ddTHH:mm:ss.fffZ
. Notice the fff
for milliseconds and HH
for 24-hour.
The following code
var settings = new JsonSerializerSettings {
DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffZ"
};
var json = JsonConvert.SerializeObject(DateTime.Now, settings);
returns
"2017-09-08T19:04:14.480Z"
The format string does not force a timezone translation. You can tell Json.NET to treat the time as Local
or Utc
through the DateTimeZoneHandling
setting:
var settings = new JsonSerializerSettings {
DateFormatString = "yyyy-MM-ddTH:mm:ss.fffZ",
DateTimeZoneHandling = DateTimeZoneHandling.Utc
};
var json = JsonConvert.SerializeObject(DateTime.Now, settings);
Returns :
"2017-09-08T16:08:19.290Z"
UPDATE
As Matt Johnson explains, Z
is just a literal, while K
generates either Z
or an offset, depending on the DateTimeZoneHandling
setting.
The format string yyyy-MM-ddTH:mm:ss.fffK
with DateTimeZoneHandling.Utc
:
var settings = new JsonSerializerSettings {
DateFormatString ="yyyy-MM-ddTH:mm:ss.fffK",
DateTimeZoneHandling = DateTimeZoneHandling.Utc
};
var json = JsonConvert.SerializeObject(DateTime.Now, settings);
Will return :
2017-09-11T9:10:08.293Z
Changing to DateTimeZoneHandling.Local
will return
2017-09-11T12:15:12.862+03:00
Which, by the way is the default behaviour of Json.NET, apart from the forced millisecond precision.
Finally, .NET doesn't have a Date
-only type yet. DateTime
is used for both dates and date+time values. You can get the date part of a DateTime with the DateTime.Date property. You can retrieve the current date with DateTime.Today.
Time of day is represented by the TimeSpan
type. You can extract the time of day from a DateTime
value with DateTime.TimeOfDay. Timespan
isn't strictly a time-of-day type as it can represent more than 24 hours.
What was that yet?
Support for explicit Date, TimeOfDay
is comming through the CoreFX Lab project. This contains "experimental" features that are extremely likely to appear in the .NET Runtime like UTF8 support, Date, String, Channles. Some of these already appear as separate NuGet packages.
One can use the System.Time classes already, either by copying the code or adding them through the experimental NuGet source
Upvotes: 101
Reputation: 41
You can try this:
DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
Upvotes: 4
Reputation: 248
In my case, i using this config in vb.net, it's so easy translate to c #
settings.NullValueHandling = NullValueHandling.Ignore
settings.DateTimeZoneHandling = DateTimeZoneHandling.Local
BE = JsonConvert.DeserializeObject(Of EN_BE)(str, settings)
I get this format date from laravel API
2020-08-02T01:41:05.000000Z
and i convert to correct value same to database
2020-08-01 20:41:05
Upvotes: 0
Reputation: 55
If, like Willie Esteche you wish to convert a number that is too low, you have probably got a Unix Date Time value. His solution does indeed work, but as of .Net Framework 4.6 there is an easier way to do things.
Given a value of 1500013000, first you convert this to a DateTimeOffset with the FromUnixTimeSeconds() method, then simply grab the DateTime component.
DateTime dt = DateTimeOffset.FromUnixTimeSeconds(1500013000).UtcDateTime;
Conversion back (assuming UTC) is performed like so:
long Udt = new DateTimeOffset(dt,TimeSpan.Zero).ToUnixTimeSeconds();
Upvotes: 1
Reputation: 39
Get current universaltime to json date time format and vice versa:
DateTime currentDateTime = DateTime.Now.ToUniversalTime();
var jsonDateTime = GetJSONFromUserDateTime(currentDateTime);
DateTime getDateTime = GetUserDateTimeFromJSON(jsonDateTime);
Here are both methods:
/// <summary>
/// Convert UserDateTime({9/7/2018 8:37:20 AM}) to JSON datetime(1536309440373) format
/// </summary>
/// <param name="givenDateTime"></param>
/// <returns></returns>
public static string GetJSONFromUserDateTime(DateTime givenDateTime)
{
string jsonDateTime = string.Empty;
if (givenDateTime != null)
{
JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
{
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
};
jsonDateTime = JsonConvert.SerializeObject(givenDateTime, microsoftDateFormatSettings);
jsonDateTime = jsonDateTime.Replace("\"\\/Date(", "").Replace(")\\/\"", "");
}
return jsonDateTime;
}
/// <summary>
/// Convert JSON datetime(1536309440373) to user datetime({9/7/2018 8:37:20 AM})
/// </summary>
/// <param name="jsonDateTime"></param>
/// <returns></returns>
public static dynamic GetUserDateTimeFromJSON(string jsonDateTime)
{
dynamic userDateTime = null;
if (!string.IsNullOrEmpty(jsonDateTime))
{
JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
{
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
};
userDateTime = JsonConvert.DeserializeObject("\"\\/Date(" + jsonDateTime + ")\\/\"", microsoftDateFormatSettings);
}
return userDateTime;
}
Upvotes: 3