【问题标题】:JSON to .Net Epoch date conversionJSON 到 .Net Epoch 日期转换
【发布时间】:2017-02-01 13:20:25
【问题描述】:

我有一个简单的 WebAPI 项目。我以 Epoch 格式传递 JSON 日期 “pickupBefore”:“/日期(1485360480-0800)/”。当 .Net 捕获它时,DateTime 显示 1970 年。 应该是 2017 年 1 月 25 日。 我应该怎么做才能实时获取?

在我的 .Net 应用程序中,我将日期捕获为 DateTime。在幕后,DateTime 结构充满了 1970 年的日期。我在该结构中寻找可以帮助我将其转换为实时 DateTime 的东西。

在提出问题之前,我确实查看并尝试了How do you convert epoch time in C#?,但这无助于解决我的问题。 谢谢

【问题讨论】:

标签: c# json asp.net-web-api


【解决方案1】:

基本问题是您的日期字符串是 Unix 纪元时间 但微软的 JSON 日期格式是 Unix 纪元时间 毫秒,如the documentation 中所述。 Json.NET 自动识别 Microsoft 格式的日期字符串,并在此过程中将偏移量解释为毫秒而不是秒,这解释了为什么 DateTime 显示 1970 年,因为 1970 年是 Unix 纪元的开始年.

您应该修复您的 JSON,以便日期格式与 Microsoft 的格式完全一致,即 "/Date(1485360480000-0800)/"。更好的是,您可以切换到 ISO 8601 format,这是目前首选的日期和时间 JSON 格式。

如果由于某种原因无法更正 JSON 格式,则需要禁用 Json.NET 的自动 DateTime 识别和解析,并创建自己的 custom JsonConverter 继承自 DateTimeConverterBase

要禁用 Json.NET 的自动日期识别,请在 JsonSerializerSettings 中设置 DateParseHandling = DateParseHandling.None。但是,如果您无法修改整体序列化程序设置,则只能通过将转换器从 Question 40632820 应用于它来禁用包含类型的日期识别,例如:

[JsonConverter(typeof(DateParseHandlingConverter), DateParseHandling.None)] // Disable Json.NET's built-in date time parsing function.
public class RootObject
{
    public DateTime pickupBefore { get; set; }
}

接下来,您需要编写自定义的JsonConverter。一种选择是复制 Newtonsoft 的 DateTimeUtils.TryParseDateTime()DateTimeUtils.TryParseDateTimeOffset() 的所有逻辑,在重写 DateTimeUtils.TryParseDateTimeMicrosoft()DateTimeUtils.TryParseDateTimeOffsetMicrosoft() 的过程中以秒而不是毫秒解析纪元数。我开始这样做,但意识到其中涉及相当多的代码 - 超过了 stackoverflow 的答案。作为替代方案,一种快速而简单的技巧是在 JSON 中插入一个额外的 000 子字符串,以将秒数转换为毫秒数,如下所示:

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();
    }
}

它并不漂亮,但确实可以完成工作。然后将转换器应用于您的类型,如下所示:

[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; }
}

或将其添加到 JsonSerializerSettings.Converters 以更改整个数据模型的 DateTime 字符串的反序列化。

示例fiddle

【讨论】:

    猜你喜欢
    • 2018-01-21
    • 1970-01-01
    • 2020-06-15
    • 2012-04-01
    • 2015-07-03
    • 2011-10-09
    • 2018-12-23
    • 2018-07-25
    • 2017-03-23
    相关资源
    最近更新 更多