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

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

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

在服务器端,在控制器内,我似乎无法通过此错误:

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

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

  public ActionResult Save(string jsonData) { var serializer = new JavaScriptSerializer(); serializer.RegisterConverters(new[] { new TimeSpanJsonConverter() }); var specs = serializer.Deserialize<List>(jsonData); return View("Index", _allTrackerJobs); } 

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

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

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


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

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


编辑 – 蹩脚的解决方案

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

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

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

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

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

为了完整性,并希望我一个小时保存其他人,这就是我能够转换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); } 

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

旧:

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

日期看起来像这样: Date(1348017917565)

新:

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

日期看起来像这样: 2012-09-18T21:27:31.1285861-04:00

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

我在互联网上找到了这段代码。 它对我来说就像一个魅力……

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

通过在Javascript日期和各种服务器端语言之间进行转换,经常捕获人们的一件事是,尽管双方都能够理解unix样式的时间戳值,但JS使用微秒精度时间戳,而在大多数其他语言中,默认值时间戳精度是第二个。

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

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

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

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

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

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

我接受了@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; } } } 

收到错误后

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

使用此替换为我工作。

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