The basic problem is that your date string is in Unix epoch time in seconds but Microsoft's JSON date format is in Unix epoch time in milliseconds, as explained in the documentation. Json.NET automatically recognizes date strings in Microsoft format and in doing so interprets the offset as being in ms not seconds, which explains why the DateTime shows year 1970, as 1970 is the beginning year of the Unix epoch.
You should fix your JSON so that the date format is completely consistent with Microsoft's format, which would be "/Date(1485360480000-0800)/"
. Better yet, you could switch to ISO 8601 format which is currently the preferred JSON format for dates and times anyway.
If for whatever reason you cannot correct your JSON format, you will need to disable Json.NET's automatic DateTime
recognition and parsing, and create your own custom JsonConverter
inheriting from DateTimeConverterBase
.
To disable Json.NET's automatic date recognition, set DateParseHandling = DateParseHandling.None
in JsonSerializerSettings
. But if you cannot modify your overall serializer settings, you can disable date recognition on the containing type only by applying the converter from Question 40632820 to it, e.g.:
[JsonConverter(typeof(DateParseHandlingConverter), DateParseHandling.None)] // Disable Json.NET's built-in date time parsing function.
public class RootObject
{
public DateTime pickupBefore { get; set; }
}
Next you will need to write your custom JsonConverter
. One option would be to duplicate all the logic of Newtonsoft's DateTimeUtils.TryParseDateTime()
and DateTimeUtils.TryParseDateTimeOffset()
, in the process rewriting DateTimeUtils.TryParseDateTimeMicrosoft()
and DateTimeUtils.TryParseDateTimeOffsetMicrosoft()
to parse epoch numbers in seconds not milliseconds. I started to do this but realized there's a fair amount of code involved - more than is appropriate for a stackoverflow answer. As an alternative, a quick-and-dirty hack would be to insert an extra 000
substring into the JSON to convert from seconds to milliseconds, like so:
public class MicrosoftSecondsDateTimeConverter : DateTimeConverterBase
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var token = JToken.Load(reader);
if (token.Type == JTokenType.String)
{
var s = ((string)token).Trim();
if (s.StartsWith("/Date(", StringComparison.Ordinal) && s.EndsWith(")/", StringComparison.Ordinal))
{
// MS datetime format is in milliseconds as is shown here:
// https://msdn.microsoft.com/en-us/library/bb299886.aspx#intro_to_json_sidebarb
// But our times are offsets in seconds.
// Convert.
var sb = new StringBuilder(""\/Date(");
var insert = "000"; // Seconds to MS
for (int i = 6; i < s.Length - 2; i++)
{
if (s[i] == '-' || s[i] == '+') // Time zone marker
{
sb.Append(insert);
insert = string.Empty;
}
sb.Append(s[i]);
}
sb.Append(insert);
sb.Append(")\/"");
s = sb.ToString();
var dt = new JsonSerializer().Deserialize(new StringReader(s), objectType);
return dt;
}
}
// Not a Microsoft date.
return new JsonSerializer().Deserialize(token.CreateReader(), objectType);
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
It's not beautiful but does get the job done. Then apply your converter to your type as follows:
[JsonConverter(typeof(DateParseHandlingConverter), DateParseHandling.None)] // Disable Json.NET's built-in date time parsing function.
public class RootObject
{
[JsonConverter(typeof(MicrosoftSecondsDateTimeConverter))]
public DateTime pickupBefore { get; set; }
}
Or add it to JsonSerializerSettings.Converters
to change deserialization of DateTime
strings for your entire data model.
Sample fiddle.