在反序列化期间将 JSON 日期转换为 .NET DateTime 的正确方法
Posted
技术标签:
【中文标题】在反序列化期间将 JSON 日期转换为 .NET DateTime 的正确方法【英文标题】:Proper Way to Convert JSON Date to .NET DateTime During Deserialization 【发布时间】:2012-09-11 01:29:33 【问题描述】:我有一个使用 JSON 数据调用 MVC 控制器的 javascript 函数:
var specsAsJson = JSON.stringify(specs);
$.post('/Home/Save', jsonData: specsAsJson );
在服务器端,在控制器内,我似乎无法克服这个错误:
/Date(1347992529530)/ 不是 DateTime 的有效值。
当我调用 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);
我一直在做一些谷歌搜索,上面的代码是我完成这项工作的最新尝试(使用来自here 的 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<EquipmentSpecDto>>(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);
【问题讨论】:
看起来您将日期对象作为字符串数据传递,而不是实际值。您需要将日期转换为毫秒。 当我 Debug.WriteLine() 我的 jsonData 变量时,它看起来已经有毫秒(为了便于阅读而被截断):["Id":1,"TrackerJob":null,"StartTime":"/Date(1347993132851)/","EndTime":"/Date(1347993132851)/",
抱歉,没有意识到 C# 有用于导入日期的特定格式。这可能会有所帮助:***.com/questions/9374557/…
【参考方案1】:
JavaScript(嗯,EcmaScript)基于 ISO-8601 标准的简化定义其 DateTime 字符串交换格式。
XML Schema 也根据 ISO-8601 定义了它的 DateTime 字符串交换格式。
我发现使用 .NET 类 System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTime
处理从 .NET DateTime 值到 XML 格式的转换以及返回非常方便。
由于 JavaScript 基于相同的 ISO-8601 标准,也许它也适用于您的 JSON 案例。
【讨论】:
嗯,也许我可以用它来挂钩 JavaScriptSerializer 的转换器,并在反序列化期间转换日期。我会试一试。 我尝试了这个,最终我不得不管理对象图的序列化,我绝对不想因为日期不匹配而参与其中。因此,转换日期似乎很简单,但并不是在反序列化过程中自动发生。不过感谢您的提示!【参考方案2】:在 Javascript 日期和各种服务器端语言之间进行转换时经常引起人们注意的一件事是,尽管双方可能都能够理解 unix 样式的时间戳值,但 JS 使用微秒精度的时间戳,而在大多数其他语言中语言的默认时间戳精度是秒。
换句话说,Javascript 中的 1347993132851 需要除以 1000 才能在其他语言中被识别为 unix 时间戳。
或者,如果您的平台可以接受格式化日期字符串,请使用 Javascript Date()
对象将时间戳值转换为格式化日期以发送到服务器。或者更好的是,使用诸如Date.js 或Moment.js 之类的帮助库。
【讨论】:
很高兴知道这一点。使用这种方法,我似乎需要在我的对象层次结构中找到所有数据属性并应用此日期转换。如果我可以在服务器上反序列化而不必查找和更新所有日期,那就太好了。【参考方案3】:我找到了一个简单的答案。在我的 javascript 中,我使用 JavaScriptSerializer 序列化数据。经过多次谷歌搜索,我发现了这个article,它展示了如何使用 JsonConvert 进行序列化,从而使用更适合 .NET 的 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,后端的反序列化就可以正常工作。
【讨论】:
【参考方案4】:我在互联网上找到了这段代码。 它对我来说就像一个魅力......
function customJSONstringify(obj)
return JSON.stringify(obj).replace(/\/Date/g, "\\\/Date").replace(/\)\//g, "\)\\\/")
【讨论】:
Newtonsoft 是解决 JSON 序列化问题的最佳方法。但是我对此表示赞成,因为它是问题的正确答案,即如何反序列化 .NET 日期。 对我来说最好的解决方案是在 Javascript 端工作并且不能使用 Newtonsoft。【参考方案5】:我接受了@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;
【讨论】:
【参考方案6】:收到错误后
/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 ()
);
【讨论】:
以上是关于在反序列化期间将 JSON 日期转换为 .NET DateTime 的正确方法的主要内容,如果未能解决你的问题,请参考以下文章