Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
257 views
in Technique[技术] by (71.8m points)

c# - JSON to .Net Epoch date conversion

I have a simple WebAPI project. I am passing JSON date in Epoch format "pickupBefore":"/Date(1485360480-0800)/". When .Net catches it the DateTime shows year 1970. It is suppose to be January 25, 2017. What should I do to get it in real time?

In my .Net application, I am catching the date as DateTime. Behind the scene the DateTime structure get filled with the date from 1970. I was looking for something in that structure that will help me to convert it to real time DateTime.

I did looked at and tried How do you convert epoch time in C#? before asking the question, but it did not help to solve my issue. Thank you

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...