C# 在反序列化期间将 JSON 日期转换为 .NET DateTime 的正确方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12482856/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 23:23:45  来源:igfitidea点击:

Proper Way to Convert JSON Date to .NET DateTime During Deserialization

c#javascriptjsonstringify

提问by Bob Horn

I have a javascript function that calls an MVC controller with JSON data:

我有一个使用 JSON 数据调用 MVC 控制器的 javascript 函数:

var specsAsJson = JSON.stringify(specs);
$.post('/Home/Save', { jsonData: specsAsJson });

On the server side, within the controller, I can't seem to get past this error:

在服务器端,在控制器中,我似乎无法克服这个错误:

/Date(1347992529530)/ is not a valid value for DateTime.

/Date(1347992529530)/ 不是 DateTime 的有效值。

That exception happens when I call Deserialize() (third line in method below):

当我调用 Deserialize() (下面方法中的第三行)时会发生该异常:

    public ActionResult Save(string jsonData)
    {
        var serializer = new JavaScriptSerializer();
        serializer.RegisterConverters(new[] { new TimeSpanJsonConverter() });
        var specs = serializer.Deserialize<List<EquipmentSpecWithParameterlessConstructor>>(jsonData);

        return View("Index", _allTrackerJobs);
    }

I've been doing some googling, and the above code is my latest attempt to make this work (using the TimeSpanJsonConverter from here). Other approaches show sending only a date to the server, but I have a list of objects that have dates as some properties.

我一直在做一些谷歌搜索,上面的代码是我最近尝试完成这项工作(使用这里的 TimeSpanJsonConverter )。其他方法显示仅向服务器发送日期,但我有一个将日期作为某些属性的对象列表。

Is there an elegant, generally-accepted approach to solving this, or do we still need some kind of ugly work-around? What's the right way to resolve this?

是否有一种优雅的、普遍接受的方法来解决这个问题,还是我们仍然需要某种丑陋的解决方法?解决这个问题的正确方法是什么?

=================== End of original question ===================

================== 原始问题结束 ====================



Edit - SOLVED by serializing using JsonConvert

编辑 - 通过使用 JsonConvert 序列化解决

See my answerbelow (not the crappy work-around in this question).

请参阅下面的答案(不是这个问题中糟糕的解决方法)。



Edit - Crappy work-around

编辑 - 糟糕的解决方法

I created a DTO with the exact same fields as the domain object, except that I made the date fields strings so they would deserialize. Now that I can deserialize it, I'll work on getting the dates into a valid format so I can create domain objects from my DTOs.

我创建了一个与域对象具有完全相同字段的 DTO,除了我创建了日期字段字符串以便它们可以反序列化。现在我可以反序列化它,我将努力将日期转换为有效格式,以便我可以从我的 DTO 创建域对象。

public class EquipmentSpecDto
{
    public string StartTime { get; set; }
    public string EndTime { get; set; }
    // more properties here
}

And I simply just used the DTO for the deserialization:

我只是使用 DTO 进行反序列化:

var specs = serializer.Deserialize<List<EquipmentSpecDto>>(jsonData);


Edit 2 - Converting JavaScript Dates to .NET

编辑 2 - 将 JavaScript 日期转换为 .NET

For completeness, and in the hopes that I save someone else an hour, this is how I was able to convert the javascript dates:

为了完整起见,并希望我能帮别人节省一个小时,这就是我能够转换 javascript 日期的方式:

    foreach (EquipmentSpecDto specDto in specDtos)
    {
        // JavaScript uses the unix epoch of 1/1/1970. Note, it's important to call ToLocalTime()
        // after doing the time conversion, otherwise we'd have to deal with daylight savings hooey.
        DateTime unixEpoch       = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        Double startMilliseconds = Convert.ToDouble(specDto.StartTime.Substring(6, 13));
        Double endMilliseconds   = Convert.ToDouble(specDto.EndTime.Substring(6, 13));
        DateTime startTime       = unixEpoch.AddMilliseconds(startMilliseconds).ToLocalTime();
        DateTime endTime         = unixEpoch.AddMilliseconds(endMilliseconds).ToLocalTime();
        EquipmentSpec spec       = new EquipmentSpec(startTime, endTime, specDto.Equipment);

        specs.Add(spec);
    }

采纳答案by Bob Horn

I found a simple answer. In my javascript, I was serializing the data using the JavaScriptSerializer. After much googling, I found this articlethat shows how to serialize using JsonConvert that causes a more .NET-friendly DateTime to be used.

我找到了一个简单的答案。在我的 javascript 中,我使用 JavaScriptSerializer 序列化数据。经过多次谷歌搜索,我发现这篇文章展示了如何使用 JsonConvert 进行序列化,这会导致使用更 .NET 友好的 DateTime。

Old:

老的:

var specs = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ViewBag.JobSpecEquipment))

Dates look like this: Date(1348017917565)

日期如下所示: Date(1348017917565)

New:

新的:

var specs = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.JobSpecEquipment));

Dates look like this: 2012-09-18T21:27:31.1285861-04:00

日期如下所示: 2012-09-18T21:27:31.1285861-04:00

So the problem was really how I was serializing in the first place. Once I used JsonConvert, deserialization on the back end simply worked.

所以问题实际上是我首先是如何进行序列化的。一旦我使用了 JsonConvert,后端的反序列化就很简单了。

回答by dthorpe

JavaScript (well, EcmaScript) defines its DateTime string interchange format based on a simplification of the ISO-8601 standard.

JavaScript(嗯,EcmaScript)基于 ISO-8601 标准的简化定义了它的 DateTime 字符串交换格式。

XML Schema defines its DateTime string interchange format based on ISO-8601 also.

XML Schema 也定义了基于 ISO-8601 的 DateTime 字符串交换格式。

I have found it handy to use the .NET class System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTimeto handle conversion from .NET DateTime values to XML formats and back.

我发现使用 .NET 类System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTime来处理从 .NET DateTime 值到 XML 格式并返回的转换很方便。

Since JavaScript is based on the same ISO-8601 standard, perhaps it will work for your JSON case as well.

由于 JavaScript 基于相同的 ISO-8601 标准,因此它可能也适用于您的 JSON 案例。

回答by Spudley

One thing that catches people out quite often with converting between Javascript dates and various server-side languages is that although both sides may be able to understand a unix-style timestamp value, JS uses microsecond-precision timestamp, whereas in most other languages the default timestamp precision is to the second.

在 Javascript 日期和各种服务器端语言之间进行转换时经常引起人们注意的一件事是,尽管双方都可能能够理解 Unix 样式的时间戳值,但 JS 使用微秒精度的时间戳,而在大多数其他语言中,默认情况下时间戳精度为秒。

In other words, 1347993132851 in Javascript needs to be divided by 1000 in order to be recognised as a unix timestamp in other languages.

换句话说,Javascript 中的 1347993132851 需要除以 1000 才能被其他语言识别为 unix 时间戳。

Alternatively, if your platform can accept formatted date strings, use the Javascript Date()object to convert a timestamp value into a formatted date to send to the server. Or even better, use a helper library such as Date.jsor Moment.js.

或者,如果您的平台可以接受格式化的日期字符串,请使用 JavascriptDate()对象将时间戳值转换为格式化的日期以发送到服务器。或者更好的是,使用辅助库,例如Date.jsMoment.js

回答by Wagner Bertolini Junior

I found this piece of code on the internet. It worked like a charm for me...

我在网上找到了这段代码。它对我来说就像一种魅力......

function customJSONstringify(obj) {
    return JSON.stringify(obj).replace(/\/Date/g, "\\/Date").replace(/\)\//g, "\)\\/")
}

回答by Tiago Freitas Leal

I took @Bob Horn answer but it wasn't working for me. My REST service is using Javascritpt dates. I adapted the referred answer to an extension method.

我接受了@Bob Horn 的回答,但它对我不起作用。我的 REST 服务使用的是 Javascritpt 日期。我将引用的答案改编为扩展方法。


using System;

namespace Mediatel.Framework
{
    public static class JsonDate
    {
        public static DateTime ConvertToDateTime(this string jsonDate)
        {
            // JavaScript uses the unix epoch of 1/1/1970. Note, it's important to call ToLocalTime()
            // after doing the time conversion, otherwise we'd have to deal with daylight savings hooey.
            DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            Double milliseconds = Convert.ToDouble(jsonDate);
            DateTime dateTime = unixEpoch.AddMilliseconds(milliseconds).ToLocalTime();

            return dateTime;
        }
    }
}

回答by BunkerBilly

After receving the error

收到错误后

/Date(1347992529530)/ is not a valid value for DateTime.

/Date(1347992529530)/ 不是 DateTime 的有效值。

using this replace worked for me.

使用这个替换对我有用。

var data = ko.toJSON({ objext: obj});
$.ajax({
    url: "/API/API.asmx/SaveObject",
    type: "POST",
    dataType: "json",
    contentType: "application/json; char-utf8;",
    data: data.replace(/\/Date/g, "\\/Date").replace(/\)\//g, "\)\\/"),
    success: function (r) {},
    error: function (e) {},
    complete: function () {}
});